前提准备

域名

开发微信网页授权时需要一个外网可以访问的域名,因为用户确认进行微信网页授权后微信服务器会通过一个回调URL向开发服务器发送一个回调请求。
开发阶段可以使用一些内网穿透工具来实现,例如:natapp、花生壳等等。
福利:natapp和花生壳都会免费赠送一些隧道。
注意:natapp提供的免费隧道每次启动客户端时产生的域名时随机的。
填坑:利用花生壳提供的域名进行内网穿透时可能会被微信拦截,所以推荐使用natapp(PS: 请测有效)。

个人订阅号

由于是进行微信网页授权,所以需要一个个人微信订阅号作为开发基础。
福利:由于微信个人订阅号没有提供微信网页授权功能,但是可以利用微信提供的测试号进行开发。
测试号在哪里:登录个人订阅号 -> 开发 -> 开发者工具 -> 公众平台测试账号
注意:整个开发过程中都是使用测试号的appID和appsecret

开发环境

JDK: 1.8
MAVEN: 3.x
SpringBoot: 2.x
IDEA: 2017专业版

微信网页授权官方文档

文档路径

文档在哪里:登录微信订阅号 -> 开发 -> 开发者工具 -> 开发文档 -> 微信网页开发 -> 微信网页授权

回调域名配置

在哪里配置:登录个人订阅号 -> 开发 -> 开发者工具 -> 公众平台测试账号 -> 网页服务 -> 网页账号 -> 修改 -> 填入授权回调页面域名即可(推荐使用natapp)

开发步骤

1 第一步:用户同意授权,获取code
2 第二步:通过code换取网页授权access_token
3 第三步:刷新access_token(如果需要)
4 第四步:拉取用户信息(需scope为 snsapi_userinfo)
5 附:检验授权凭证(access_token)是否有效

Java代码实现

进入微信授权页面

只需要通过微信浏览器访问到微信授权的页面即可。
思路
01 用户通过微信浏览器进入一个页面
02 点击一个按钮向开发者后台发送一个GET请求
03 开发这个后台封装一个URL并重定向到这个URL
代码片段

    /**
     * 微信网页授权逻辑入口
     * @param map
     */
    @GetMapping(value = "/auth")
    public void toAuth(ModelMap map, HttpServletRequest request, HttpServletResponse response) throws IOException {
        log.info("进入微信授权逻辑......");
//        微信网页授权第一步 - 用户同意授权,获取code - start
        String getCodeUrl = weixinBaseInfoProperties.getAuth().getGetCodeUrl();
        String appid = weixinBaseInfoProperties.getAppid();
        String appsecret = weixinBaseInfoProperties.getAppsecret();
        String redirectUri = weixinBaseInfoProperties.getAuth().getRedirectUri();
        String scope = weixinBaseInfoProperties.getAuth().getScope();
        getCodeUrl = getCodeUrl.replace("APPID", appid)
                .replace("REDIRECT_URI", redirectUri)
                .replace("SCOPE", scope);
        log.info("封装好的getCodeUrl为:" + getCodeUrl);
        response.sendRedirect(getCodeUrl);
//        微信网页授权第一步 - 用户同意授权,获取code - end
    }

获取CODE和AccessToken、用户openid、用户信息

微信用户通过微信浏览器确认授权后,微信服务器会通过之前设定的回调URL向开发者后台发送一个GET请求,这个请求中携带了CODE信息。
思路
01 用户确认授权
02 微信服务器发送回调请求
03 开发服务器接收到回调请求
04 获取CODE
05 通过CODE在拼装一个url去请求微信服务器来获取access_token、openid
06 通过access_token、openid封装一个url去请求微信服务器来获取用户信息

微信网页授权的使用场景

直接利用微信账号作为网页账号

获取用户信息成功后直接跳转到目标页面即可

微信账号和网站账号进行绑定

思路:
01 获取用户信息成功
02 根据用户openid到数据库中去查找网页账号信息
03 如果查找到信息就说明已经绑定,直接跳转拿到目标页面即可
04 如果没有获取到就跳转到登录绑定页面
05 用户输入账号和密码并提交到开发者后台
06 后台需对网站账号合法性进行校验
07 校验通过后进行绑定操作
08 跳转到目标页面
代码片段一

    /**
     * 回调页面
     * @param map
     * @return
     */
    @GetMapping(value = "/callback")
    public String callback(ModelMap map, HttpServletRequest request, HttpServletResponse response) {
        log.info("进入回调处理逻辑......");
        String appid = weixinBaseInfoProperties.getAppid();
        String appsecret = weixinBaseInfoProperties.getAppsecret();

//        微信网页授权第二步 - 通过code换取网页授权access_token - start
        StringBuffer requestURL = request.getRequestURL();
        log.info("进入回调处理逻辑的请求url为:" + requestURL);
        String code = request.getParameter("code");
        log.info("获取到的用于换取access_token的票据的code值为:" + code);

        String getAccessTokenUrl = weixinBaseInfoProperties.getAuth().getGetAccessTokenUrl();
        getAccessTokenUrl = getAccessTokenUrl.replace("APPID", appid)
                .replace("SECRET", appsecret)
                .replace("CODE", code);
        log.info("封装好的用于获取accessToke的url为:" + getAccessTokenUrl);
        String getAccessTokenResponseStr = httpUtils.doGetStrByRestTemplate(getAccessTokenUrl);
        log.info("发送获取access_token请求后的响应为STR:" + getAccessTokenResponseStr);
        GetAuthAccessTokenResponse getAuthAccessTokenResponse = transformerUtils.String2Object(getAccessTokenResponseStr, GetAuthAccessTokenResponse.class);
        log.info("发送获取access_token请求后的响应为:" + getAuthAccessTokenResponse);
        String access_token = getAuthAccessTokenResponse.getAccess_token();
        String open_id = getAuthAccessTokenResponse.getOpenid();
//        微信网页授权第二步 - 通过code换取网页授权access_token - end

//        微信网页授权第四步 - 拉取用户信息(需scope为 snsapi_userinfo) - start
        String getUserInfoUrl = weixinBaseInfoProperties.getAuth().getGetUserInfoUrl();
        getUserInfoUrl = getUserInfoUrl.replace("ACCESS_TOKEN", access_token)
                .replace("OPENID", open_id);
        log.info("封装好的用于获取userInfo的url为:" + getUserInfoUrl);
        String getUserInfoResponseStr = httpUtils.doGetStrByRestTemplate(getUserInfoUrl);
        log.info("发送获取userInfo请求后的响应为STR:" + getUserInfoResponseStr);
        GetUserInfoResponse getUserInfoResponse = transformerUtils.String2Object(getUserInfoResponseStr, GetUserInfoResponse.class);
        log.info("发送获取userInfo请求后的响应为:" + getUserInfoResponse);
//        微信网页授权第四步 - 拉取用户信息(需scope为 snsapi_userinfo) - end

//        第一种使用:直接使用微信的用户用户体系
//        map.addAttribute("userinfo", getUserInfoResponse);
//        return "index2";

//        第二种:微信用户和网站用户进行绑定
//        根据openid查询网站的账户信息
        UserBindDO userBindDOByOpenid = userBindRepository.findByOpenid(getUserInfoResponse.getOpenid());
        if (userBindDOByOpenid != null) {
//            已经绑定过的情况
            log.info("已经绑定过啦");
            map.addAttribute("userinfo", userBindDOByOpenid);
            return "index3";
        } else {
//            没有绑定过的情况
            log.info("还未进行绑定操作");
            map.addAttribute("openid", getUserInfoResponse.getOpenid());
            map.addAttribute("nickname", getUserInfoResponse.getNickname());
            return "login";
        }
    }

代码片段二

    @PostMapping(value = "/login")
    public String login(UserBindDO userBindDO, ModelMap map) {
        log.info("获取到的参数信息为:" + userBindDO);
//        TODO: 对账户信息进行格式校验,如果格式不正确直接返回登录绑定页面
//        TODO: 验证账户是否存在, 如果不存在直接跳转到注册页面(微信用户信息同时返回),在注册逻辑中直接进行绑定
//        TODO: 验证账户密码是否正确,如果部正确直接返回登录绑定页面
        UserBindDO save = userBindRepository.save(userBindDO);
        if (save != null) {
            log.info("bind - 绑定成功");
            log.info("绑定后的结果信息为:" + save);
            map.addAttribute("userinfo", save);
            return "index3";
        } else {
            log.info("bind - 绑定失败");
            return "login";
        }
    }

源代码

  扫码获取

微信公众号03 微信网页授权-LMLPHP

01-14 03:36