上一篇,進行了微信公衆號的服務器配置,下面開始微信公衆號的網頁授權
通過官網的文檔,可以知道網頁授權大致分爲幾步
這裏我們暫且不考慮刷新網頁授權的access_token。
第一步獲取code,這個code 可以看作是一個預授權碼,官方說法是一個用來換取access_token的票據,下面是第一步所需要的參數
第一個appid這個就是你公衆號的標識,等於你要告訴微信,用戶正在登錄哪個公衆號;回調地址,這個就是微信返回給你code的地址,等於你告訴微信你發code到這個地址上;sope,這個看需求,只是獲取openid就用snsapi_base,需要個人信息的用snsaapi_userinfo;最後帶上#wechat_redirect。記住參數的順序不要錯,微信服務器會做校驗
https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect
下面上代碼
/**
* @description 獲取回調中的code(這個可以讓前端直接去請求這個url,而不是讓後端做重定向)
* @author zhou
* @param
* @return
* @date 2019/6/8
*/
@GetMapping(value = "/preAuth")
public void preAuth(HttpServletResponse response) {
//拼接請求地址
StringBuilder sb = new StringBuilder(WxOaUrlConfig.API_PRE_AUTH);
sb.append("appid=").append(wxOfficialsAccountConfiguration.getAppid())
.append("&").append("redirect_uri=").append(EncoderUtil
.UrlEncode(wxOfficialsAccountConfiguration.getRedirectUrl()))
.append("&").append("response_type=code")
//獲取用戶信息
.append("&").append("scope=snsapi_userinfo")
.append("&").append("state=4959a8b50e8e41ad")
.append("#wechat_redirect");
String url = sb.toString();
try {
//httpUtil.doGetJson(url);
response.sendRedirect(url);
} catch (IOException e) {
log.error(e.getMessage());
throw new HttpException(HttpErrorEnum.REQUEST_ERROR);
}
}
也是比較簡單的按順序拼接好url然後以https協議重定向。(也可以讓前端去請求)
第二步
在微信端同意授權後,在回調地址接受code
appid介紹過了,code可以從回調請求的參數中獲取,secret是公衆號的密鑰開發時保存在後端。
/**
* @description 授權回調
* @author zhou
* @param
* @return
* @date 2019/6/8
*/
@GetMapping(value = "/authCallback")
public WebResponse authCallBack(HttpServletRequest request){
String code = request.getParameter("code");
//獲取網頁授權的accessToken
JSONObject tokenObject = wxOfficialAccountService.getWebAccessToken(code);
if(!tokenObject.containsKey("access_token")){
log.error(tokenObject.getString("errmsg"));
throw new WxErrorException(tokenObject.getInteger("errcode"),tokenObject.get("errMsg").toString());
}
WebResponse webResponse = wxOfficialAccountService.loginInfo(tokenObject);
return webResponse;
}
/**
* @description 獲取網頁授權的accessToken
* @author zhou
* @param code 預授權碼
* @return jsonObject
* @date 2019/6/8
*/
@Override
public JSONObject getWebAccessToken(String code) {
//拼裝url
StringBuilder sb = new StringBuilder(WxOaUrlConfig.API_WEB_ACCESS_TOKEN);
sb.append("appid=").append(wxOfficialsAccountConfiguration.getAppid())
.append("&").append("secret=").append(wxOfficialsAccountConfiguration.getAppsecret())
.append("&").append("code=").append(code)
.append("&grant_type=authorization_code");
String url = sb.toString();
JSONObject jsonObject = null;
try {
jsonObject = httpUtil.doGetJson(url);
} catch (IOException e) {
e.printStackTrace();
}
return jsonObject;
}
同樣拼裝url進行請求,這裏可以獲得access_token.這個就是獲取個人信息的憑證,它的有效期是兩小時,在有效期內可以直接調用去請求個人信息。所以在獲取後可以選擇保存在第三方緩存中,比如redis中
第三步獲取用戶信息
/**
* @description 登錄
* @author zhou
* @param tokenObject 網頁授權token信息
* @return webResponse
* @date 2019/6/9
*/
@Override
@Transactional(rollbackFor = Exception.class)
public WebResponse loginInfo(JSONObject tokenObject) {
//網頁授權token存入redis
redisUtil.set(tokenObject.getString("openid"),tokenObject.getString("access_token"),
(long) 7200);
//拼裝請求url
StringBuilder sb = new StringBuilder(WxOaUrlConfig.API_USER_INFO);
sb.append("access_token=").append(tokenObject.getString("access_token"))
.append("&").append("openid=").append(tokenObject.getString("openid"))
.append("&").append("lang=zh_CN");
String url = sb.toString();
OaUserVO oaUserVO = new OaUserVO();
try {
//獲取用戶信息
JSONObject jsonResult = httpUtil.doGetJson(url);
if(jsonResult.containsKey("errmsg")){
//含有錯誤信息
log.error(jsonResult.getString("errmsg"));
throw new WxErrorException(jsonResult.getInteger("errcode"),
jsonResult.getString("errmsg"));
}else{
OaUser oaUser = OaUser.builder()
.avatar(jsonResult.getString("headimgurl"))
.city(jsonResult.getString("city"))
.country(jsonResult.getString("country"))
.createTime(LocalDateTime.now())
.deleted(false)
.nickName(jsonResult.getString("nickname"))
.openid(jsonResult.getString("openid"))
.province(jsonResult.getString("province"))
.refreshTime(LocalDateTime.now())
.refreshToken(tokenObject.getString("refresh_token"))
.sex(jsonResult.getShort("sex"))
.unionid(jsonResult.containsKey("unionid")?jsonResult.getString("unionid"):null)
.privilege(jsonResult.getString("privilege"))
.updateTime(LocalDateTime.now())
.build();
oaUserRepository.saveAndFlush(oaUser);
oaUserVO.setAvatar(jsonResult.getString("headimgurl"));
oaUserVO.setNickname(jsonResult.getString("nickname"));
oaUserVO.setOpenid(jsonResult.getString("openid"));
oaUserVO.setUserId(oaUser.getUserId());
}
} catch (Exception e) {
log.error("登錄失敗");
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
throw new WeChatOaException(WeChatOaErrorEnum.AUTH_LOGIN_ERROR);
}
return WebResponse.success(oaUserVO);
}
同樣的也是拼裝成url請求數據,將請求的數據存入數據庫中。這個也比較簡單,歸納一下,就是按照文檔,請求數據入庫。
到此微信公衆號網頁授權結束。