微信公众号访问第三方网页授权流程
场景
某医院官网微信公众号,需要添加一个“个人报告”菜单,点击跳转到第三方网页,提供查询缴费记录、影像报告等功能。
公众号网页授权流程
第三方网页有自己的身份认证框架,前端 VUE ,后端 Spring Boot 。
代码实现(前端处理回调地址)
用户在微信客户端中访问第三方网页,若后端校验当前用户未登录,返回 401 状态码和微信授权页面 url 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint
{
private final SecurityProperties properties;
public void commence(HttpServletRequest request, HttpServletResponse httpServletResponse, AuthenticationException e)
throws IOException
{
httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
httpServletResponse.setHeader("Cache-Control","no-cache");
httpServletResponse.setStatus(200);
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setContentType("application/json");
// 返回微信授权页面URL
httpServletResponse.getWriter().println(JSONUtil.parse(ApiResponse.ofStatus(HttpStatus.UNAUTHORIZED, properties.getAuthurl())));
httpServletResponse.getWriter().flush();
}
}redirect_uri 授权后重定向的回调链接地址, 请使用 urlEncode 对链接进行处理。
用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE 。
redirect_uri 回调地址应该由前端处理还是后端处理?
由前端处理,前端拿到 code 授权码后请求后端登陆地址获取 token ,可以避免使用轮询的方式获取 token 。
前端接收到 401 状态码后,跳转到微信授权页面 url ,用户同意授权后,处理授权后重定向的回调链接地址 redirect_uri/?code=CODE&state=STATE。
code 作为换取 access_token 的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。
前端拿到 code 和 state 参数后请求后端接口,由后端换取 access_token 并获取用户信息。
由于公众号的secret和获取到的access_token安全级别都非常高,必须只保存在服务器,不允许传给客户端。后续刷新access_token、通过access_token获取用户信息等步骤,也必须从服务器发起。
后端根据 code 参数换取 access_token ,获取用户信息,并且通常需要对用户信息进行一些业务逻辑的处理,例如保存用户信息到数据库、授权登录等,最后返回 token 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public ApiResponse<String> greetUser( { String appid, String code, String state)
if (!this.wxService.switchover(appid)) {
throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
}
WxOAuth2AccessToken accessToken = wxService.getOAuth2Service().getAccessToken(code);
WxOAuth2UserInfo user = wxService.getOAuth2Service().getUserInfo(accessToken, null);
// 创建或更新用户
WxUser wxUser = BeanUtil.copyProperties(user, WxUser.class);
WxUser exist = wxUserService.getOne(Wrappers.<WxUser>lambdaQuery().select(WxUser::getId).eq(WxUser::getOpenid, wxUser.getOpenid()));
if (exist == null) {
wxUser.setId(IdUtils.getSnowflakeId());
wxUserService.save(wxUser);
} else {
wxUser.setId(exist.getId());
wxUserService.updateById(wxUser);
}
// 微信用户授权获取用户信息成功后,返回token
LoginUser loginUser = LoginUser.builder().openId(user.getOpenid()).userId(wxUser.getId()).wxOAuth2UserInfo(user).build();
String token = tokenService.createToken(loginUser);
return ApiResponse.ofSuccess(token);
}
后端处理回调地址(不推荐做法)
微信授权页面 url 的 redirect_uri 参数填写后端地址,由后端处理授权后重定向的回调链接地址 redirect_uri/?code=CODE&state=STATE ,由后端携带 token 参数重定向到前端。
1 |
|
前端打开微信授权页面 url ,用户同意授权后,先是有微信公众号服务端重定向到后端回调地址,后端处理完后再回调到前端地址,经历了两次重定向。
参考
微信公众号网页授权官方文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html