微信扫码登录实现

x33g5p2x  于2022-02-12 转载在 其他  
字(3.3k)|赞(0)|评价(0)|浏览(191)

需求

使用微信扫码登录的授权方式登录系统

实现

此扫码登陆过程中使用了,微信开放平台(需支付300开通开发者认证)的网站应用实现的。

官方文档:https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html

流程:

大概就是:前端调接口获取后端生成的state(可以用验证登录授权的有效性)——>用户扫码后确认授权——>前端开始调用微信开放平台的接口之后回调服务端接口——>回调时传入了两个参数,code和state——>根据code,appid和appSecret调用接口获取access_token——根据access_token获取微信用户的个人信息

代码:

前端vue:
安装一个插件:
npm install vue-wxlogin --save-dev
引入组件:
<wxlogin
         appid="xxxxxx"
         :scope="'snsapi_login'"
         theme="black"
         redirect_uri="redirectUrl"
         :state="xxxxxx"
         :self_redirect="'true'"
         rel="external nofollow"
         />

注:重定向地址需要使用urlEncode对链接进行处理

后端SpringBoot:
后端生成state接口
@ApiOperation(value = "企业端:获取扫码登录的state", notes = " \n author:ZhuGuangLiang")
@AnonymousGetMapping("/wx/qrcode")
public Result<Object> getQrCode() throws IOException {
    //生成票据
    String state= IdUtil.simpleUUID();
    //可以将state参数作为存放在redis中的授权用户信息key键
    redisUtils.set(state, JSON.toJSON(new CompanyWxDTO()), 5 * 60);
    return Result.success(state);
}
回调接口,并携带state和code参数

注:回调接口,尽量不要抛出异常,异常可以在登录接口抛出

@ApiOperation(value = "企业端:微信用户授权后,回调地址", notes = " \n author:ZhuGuangLiang")
@AnonymousGetMapping("/wx/callback")
public void callback(String code, String state) {
    companyAuthService.callback(code, state);
}
//方法中所有第三方接口都可在官方文档中找到
@Override
public void callback(String code, String state) {
    //authurl获取access_token的接口,可以看官方文档中的第二步
    JSONObject resultAuthUrl = JSONObject.parseObject(HttpUtil.get(String.format(authUrl, appid, secret, code)));
    boolean isSuccess = true;
    if (resultAuthUrl.containsKey("errcode")) {
        log.error("授权失败");
        isSuccess = false;
        //			throw new BadRequestException(ResultEnum.USER_NO_AUTH);
    }
    String openid = resultAuthUrl.getString("openid");
    String accessToken = resultAuthUrl.getString("access_token");
    String refreshToken = resultAuthUrl.getString("refresh_token");
    //根据code获取access_toke
    LambdaQueryWrapper<SpiritCompanyUser> queryWrapper = new LambdaQueryWrapper<>();
    queryWrapper.eq(SpiritCompanyUser::getOpenid, openid);
    CompanyWxDTO companyWxDTO = loginUtils.noExceptinCheckCompanyUser(queryWrapper);
    int type = companyWxDTO.getType();
    if (!isSuccess) {
        //登录失败,此时我使用type类型去记录每一种异常
        companyWxDTO.setType(7);
    }
    if (type == 1 && isSuccess) {
        //校验授权凭证
        JSONObject resultCheckToken = JSONObject.parseObject(HttpUtil.get(String.format(checkTokenUrl, accessToken, openid)));
        if (resultCheckToken.getInteger("errcode") == 40003) {
            //刷新token,防止出现token失效
            JSONObject resultRefreshToken = JSONObject.parseObject(HttpUtil.get(String.format(refreshTokenUrl, appid, refreshToken)));
            accessToken = resultRefreshToken.getString("access_token");
        }
        //获取用户信息
        JSONObject resultUserInfoUrl = JSONObject.parseObject(HttpUtil.get(String.format(userInfoUrl, accessToken, openid)));
        log.info("resultUserInfoUrl:" + resultUserInfoUrl.toString());
        if (resultUserInfoUrl.containsKey("errcode")) {
            log.error("获取用户信息失败");
            //同上
            companyWxDTO.setType(8);
        }
        companyWxDTO.setAvatarUrl(resultUserInfoUrl.getString("headimgurl"));
        companyWxDTO.setNickName(resultUserInfoUrl.getString("nickname"));
        companyWxDTO.setOpenid(openid);
        companyWxDTO.setUnionid(resultUserInfoUrl.getString("unionid"));
        log.info("微信用户授权成功");
    }
    companyWxDTO.setTicket(state);
    redisUtils.set(state, JSON.toJSON(companyWxDTO), 5 * 60);
}

相关文章