ZPY博客

微信扫码后进入公众号的H5页面的用户授权登录问题

前两个月遗留下来的bug。今天刚刚把它解决了。

要实现的效果是,用微信扫一扫,然后就会进入公众号界面,根据你二维码里关联的作品,这里公众号会推送你作品的消息,点击消息后会进入后作品的详细页面,可以购买什么的。

前面的这些都没问题,就是点击消息后不会直接进入作品的页面,而是进入了商城的首页,这是因为现在的代码里在作品页面里需要用到用户的一些情报,来判断是否购买过啊之类的,所以如果没有取到用户情报的话就返回首页。

所以现在的问题就变成了,如何在进入作品页面时,先调用微信的api来弹出用户授权画面,授权成功后上面的问题就自然解决了。

根据微信的官方文档,调用下面的这个api可以弹出用户授权画面。

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

其中需要注意的参数是redirect_uri,这个参数是授权后重定向回调链接地址,也就是说,调用上面的api后会进入到这个url。我希望的是用户授权后直接进入到作品详情画面,那么很显然,redirect_uri这个参数我直接设为作品详情的url。

然后就简单了,将原来代码里取不到用户情报时,返回首页注释掉,换成调用上面的api即可。代码如下:

StringBuffer url = request.getRequestURL();
System.out.println("授权" + url);
String redirect_uri = URLEncoder.encode(url.toString(), "utf-8");
String wecharUrl = USER_INFO_URL.replace("APPID", APPID).replace("REDIRECT_URI", redirect_uri).replace("SCOPE", SCOPE).replace("STATE", url);
response.sendRedirect(wecharUrl);

这时会再次进入这个方法,并且会带上两个参数,一个是code,一个state。这就表明授权成功了。这样虽然解决了授权的问题,但是测试时发现了另一个问题,那就是这个方法会无限执行。这是因为虽然授权成功了,但是用户情报没有存在session里,这个方法里取用户情报是从session里取的。了解这个之后,只需在这个函数的开头里判断下code和state取到没有,如果取到,则利用code参数和微信提供的access_token接口把用户情报往session里设定即可。代码如下:调用自己写的共通方法authorization2。

AccessTokenUtil.authorization2(request, response, wechatService);

authorization2方法具体实现:

public static void authorization2(HttpServletRequest request, HttpServletResponse response, WechatService wechatService) {
        //判断是否有session
        HttpSession session = request.getSession(true);
        Object obj = session.getAttribute("member");
        if (obj != null) {
//            System.out.println("已有session无需授权" + request.getRequestURL());
            return;
        }

        try {
            String code = request.getParameter("code");
            String state = request.getParameter("state");
            //判断是否有参数
            if (StringUtils.isNotEmpty(code) && StringUtils.isNotEmpty(state)) {
                // 这里则获取到了登陆成功后的结果code.
                // 通过code 获取到微信的唯一标识access_token(这里是用于网页授权的access_token)
                String getTokenUrl = GET_TOKEN_URL.replace("APPID", APPID).replace("SECRET", SECRET).replace("CODE", code);
                String result = HttpUtil.httpURLConectionGET(getTokenUrl, null);
                JSONObject tokenObject = JSONObject.parseObject(result);
//                System.out.println("获取access_token和openid :" + tokenObject.toString());
                if (!tokenObject.containsKey("errcode")) {
                    Member member = wechatService.authorization(tokenObject);
                    //手工调用session.invalidate方法,摧毁session
                    session.invalidate();
                    HttpSession session1 = request.getSession(true);
                    session1.setAttribute("member", member);
                    session1.setAttribute("member_json", JSON.toJSONStringWithDateFormat(member, "yyyy-MM-dd"));
                    if (!state.equals(REDIRECT_URI)){
//                        System.out.println("重定向" + state+"  "+member.toString());
//                        response.sendRedirect(state);
                    }
                    return;
                }
            }
            StringBuffer url = request.getRequestURL();
            if(!StringUtils.isEmpty(request.getQueryString())) {
            	url.append("?");
            	url.append(request.getQueryString());
            }
            System.out.println("授权" + url);
//            String redirect_uri = URLEncoder.encode(REDIRECT_URI, "utf-8");
            String redirect_uri = URLEncoder.encode(url.toString(), "utf-8");
            String wecharUrl = USER_INFO_URL.replace("APPID", APPID).replace("REDIRECT_URI", redirect_uri).replace("SCOPE", SCOPE).replace("STATE", url);
            response.sendRedirect(wecharUrl);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

到此,已经搞定。另外说一句,用微信实际测试时,是不会弹出授权的那个画面时,只会进度条走两次,这其实就是已经授权了。具体解释参考官方文档:

对于已关注公众号的用户,如果用户从公众号的会话或者自定义菜单进入本公众号的网页授权页,即使是scopesnsapi_userinfo,也是静默授权,用户无感知。