这几天微信公众号网页项目前后端对接到最后阶段,差微信授权登录就基本完成,结果卡了几天,总算解决。

对于微信公众平台文档,一定要认真细读,这里就挑重点说下【文档传送门】。

1 第一步:用户同意授权,获取code

2 第二步:通过code换取网页授权access_token

3 第三步:刷新access_token(如果需要)

4 第四步:拉取用户信息(需scope为 snsapi_userinfo)

1 第一步:用户同意授权,获取code

这里获取code,是由前端引导用户实现获取。微信提供的获取方式是

参考链接(请在微信客户端中打开此链接体验):
scope为snsapi_base
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=https%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdapter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_base&state=123#wechat_redirect

scope为snsapi_userinfo
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=http%3A%2F%2Fnba.bluewebgame.com%2Foauth_response.php&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect

现在说下如何引导?
参看OAuth流程的时候,也看到 引导 这个词,具体如何引导,一开始我做的处理是后台使用SpringMVC拦截所有请求,如果没有授权的则在后台使用如上链接获取code,最终返回一个token给前端。

问题恰恰出现在这里,直接返回token给前端时,因为微信授权需要重定向,异步请求无法处理重定向,所以只能主动跳转,而主动跳转后前端拿到了token,却无法继续访问原先的请求。(因为是后端拦截后做的跳转)

于是翻阅了网上很多关于Oauth的博客,在这如何 引导 用户进入授权流程上却没有明确说明(更主要是我悟性太低),终于在github上一个开源项目找到了。他做的处理是在首页打开时就判断cookie中是否存在token,如果没有则由前端主动跳转到授权页面,也就是重定向到上面微信获取code的链接。
部分vue示例代码如下:

created() {
//如果url里有token, 设置进cookie
var token = this.$route.query.token;
if(typeof token !== 'undefined') {
var exp = new Date();
  exp.setTime(exp.getTime() + 3600 * 1000);//过期时间60分钟
  document.cookie = 'token=' + token + ";expires=" + exp.toGMTString();
}
//获取token,前端主动跳转到微信获取code的链接——tokenUrl,这里最好由后端封装好一个接口,不要直接暴露整个链接。
//returnUrl是传给后端用来跳转回前端页面的地址
if(getCookie('token') == null) {
   location.href = config.projectUrl + '/auth?returnUrl=' +  encodeURIComponent(config.projectUrl + '/#/');
}

后台封装的接口

@RequestMapping("/auth")
public String auth(String returnUrl, HttpServletResponse response) throws IOException {
    return "redirect:" + 
            String.format("https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect", 
            this.wxAppId, URLEncoder.encode(this.wxRedirectUri), "snsapi_userinfo", returnUrl);
}

2 第二步:通过code换取网页授权access_token

那么如何获取后的code怎么拿到呢?这里要提到微信获取code链接传参中有一个 redirect_uri ,这就回调地址就是用来接收code的,现在后端需要提供一个接口如 /login ,于是redirect_uri可以写成 项目地址/login ,此外需要要encode转下编码。
部分Java示例代码如下:

@RequestMapping("/login")
public String login(
        @RequestParam(name="code") String code,
        @RequestParam(name="state", required=false) String state,
        HttpServletResponse servletResponse
        ) {...}

可以注意到方法签名中多了state这个形参,在 /auth 接口的方法中将前端传的returnUrl作为state的值传过来。

微信定义state:重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节

所以我们利用这个state来传跳回前端页面的地址。
现在拿到code了,可以换access_token,取到用户信息了

String accessToken = httpRequest.doGet("https://api.weixin.qq.com/sns/oauth2/access_token?appid="+APPID+"&secret="+APPSRECT+"&code="+code+"&grant_type=authorization_code");

3 第三步:刷新access_token(如果需要)

因为access_token很快过期,所以利用数据库和redis存储access_token,需要时查询数据库获取即可。

4 第四步:拉取用户信息(需scope为 snsapi_userinfo)

拿到access_token后,利用Gson获取阿里的JSON转成对象就可以获取用户信息了。
这里后端用redis生成100分钟的token返回给前端,同时用上述提到的state重定向回到前端页面,前端一拿到token就可进行存cookie的处理,以后每次请求头中带token便可通过认证了。

return "redirect:" + state + "?token=" + token;

项目地址:https://github.com/hdonghong/mrkt
若项目对您有所帮助,还请给个star或者赞,这是对我最大的鼓励。

Logo

前往低代码交流专区

更多推荐