上一篇,进行了微信公众号的服务器配置,下面开始微信公众号的网页授权
通过官网的文档,可以知道网页授权大致分为几步
这里我们暂且不考虑刷新网页授权的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请求数据,将请求的数据存入数据库中。这个也比较简单,归纳一下,就是按照文档,请求数据入库。
到此微信公众号网页授权结束。