三步实现微信小程序登录

三步实现微信小程序登录

一、登录流程:

上面这个是微信官方给出的。在通过 wx.login() 获取到用户登录态之后,需要维护登录态。开发者要注意不应该直接把 session_key、openid 等字段作为用户的标识或者 session 的标识,而应该自己派发一个 session 登录状态。详见下面的流程图:

1.前端调用wx.login()获取code值(developers.weixin.qq.com/miniprogram... 2.前端通过调用wx.getUserInfo获取iv、rawData、signature、encryptedData等加密数据,传递给后端(developers.weixin.qq.com/miniprogram...; 3.服务器通过code请求api换回session_key和openid; 4.服务器通过前端给的rawData 加获取的session_key使用sha1加密,计算出signature1; 5.比对前端传的signature和自己算出来的signature1是否一致(防止数据不一致); 6.用AES算法解密encryptedData里的敏感数据; 7.拿着敏感数据后做自己的逻辑; 8.通知前端登陆成功;

二、首先调用wx.login获取 临时登录凭证 code

ini 复制代码
wx.login({
  success: res => {
    // 获取到用户的 code:res.code
    const code = res.code;
    console.log("用户的code:" + res.code);
    //传入code调用服务端接口登录
    return api.userLogin.registerOrLogin({ code });
  }
})

Taro 框架 是一个开放式跨端跨框架解决方案(关于taro相关文档可以参考:taro-docs.jd.com/docs/),支持使用 React/Vue/Nerv 等框架来开发应用。taro基本上做到了将微信小程序上的api都封装了,同时也紧随着小程序的更新。这个地方也可以用taro来调用:

javascript 复制代码
const requestLogin = async () => {
  const { code } = await Taro.login();
  console.log("requestLogin code", code);
  return api.userLogin.registerOrLogin({ code });
};

三、服务端后台根据code获取openId、session_key和unionId:

less 复制代码
@PostMapping("/user-login/action/registerOrLogin")
public Response<LoginVO> registerOrLogin(@RequestBody UserLoginDTO userLoginDTO) {
  return ResponseUtils.returnObjectSuccess(userLoginService.registerOrLoginByInfo(userLoginDTO));
}
less 复制代码
public LoginVO registerOrLoginByInfo(UserLoginDTO userLoginDTO) {
    UserAccount userAccount = new UserAccount();
    result = authorizationGrantApi.wxMiniGrant(dto.getCode());
    if (result != null) {
        if (StringUtils.hasText(result.getOpenId())) {
            userAccount.setOpenId(result.getOpenId());
        }
        if (StringUtils.hasText(result.getUnionId())) {
            userAccount.setUnionId(result.getUnionId());
        }
    }
    
    if (StringUtils.hasText(dto.getEncryptedData()) && StringUtils.hasText(dto.getIv())) {
    ObjectNode userNode = weChatMiniGrantApi.decryptUser(dto.getEncryptedData(), result.getAuthorId(), dto.getIv());
    //基本信息
    if (userNode.get("openId") != null) {
        userAccount.setOpenId(userNode.get("openId").textValue());
        userAccount.setGender(userNode.get("gender").intValue());
        userAccount.setNickName(userNode.get("nickName").textValue());
        userAccount.setAvatar(userNode.get("avatarUrl").textValue());
        if (userNode.get("unionId") != null) {
            userAccount.setUnionId(userNode.get("unionId").textValue());
        }
    } else {
        userAccount.setUserPhone(userNode.get("phoneNumber").textValue());
    }
    
    LoginVO vo = new LoginVO();
    vo.setUserAccount(userAccount);
    ..........
    return vo;
}

其中的authorizationGrantApi.wxMiniGrant(dto.getCode())实现了根据code获取openId和unionId:

csharp 复制代码
/**
 * 微信小程序授权
 *
 * @param header
 * @param authCode
 * @return
 */
public AuthorizerGrantResult wxMiniGrant(YryzRequestHeader header, String authCode) {
    return this.wxMiniGrantAndDecryUser(header, authCode, null, null);
}

public AuthorizerGrantResult wxMiniGrantAndDecryUser(String authCode, String encryptedData, String iv) {
    if (weChatMiniGrantApi == null) {
        throw new BusinessException("", "暂未开放微信小程序授权");
    }

    //根据code,调用code2Session得到openid, session_key和unionId
    JsonNode respNode = weChatMiniGrantApi.miniGrant(authCode);

    /**
     * 转换基本参数
     */
    AuthorizerGrantResult base = new AuthorizerGrantResult();
    base.setOpenId(respNode.get("openid").textValue());
    if(respNode.get("unionid") != null){
        base.setUnionId(respNode.get("unionid").textValue());
    }
    base.setChannelId(IAuthorizerGrantHook.WX_MINI);

    /**
     * 解密用户信息数据
     */
    if (StringUtils.hasText(encryptedData) && StringUtils.hasText(iv)) {
        ObjectNode userNode = weChatMiniGrantApi.decryptUser(encryptedData, respNode.get("session_key").textValue(), iv);
        //基本信息
        AuthorizerGrantResult.ChannelAuthor channelAuthor = new AuthorizerGrantResult.ChannelAuthor(userNode);
        channelAuthor.setAvatar(userNode.get("avatarUrl").textValue());
        channelAuthor.setGender(userNode.get("gender").intValue());
        channelAuthor.setNickName(userNode.get("nickName").textValue());
        channelAuthor.setPhone(userNode.get("phoneNumber").textValue());
        base.setChannelAuthor(channelAuthor);
    }
    return authorizerGrantHook.successAfter(header, IAuthorizerGrantHook.WX_MINI, base, respNode);
}

上面代码中的wxMiniGrantAndDecryUser首先根据传入的code调用调用code2Session得到openid, session_key和unionId,然后从encryptedData和iv数据解密得到用户数据信息。解密用户数据信息是调用的decryptUser函数,其实现代码如下:

四、解密encryptedData数据得到用户信息:

ini 复制代码
public ObjectNode decryptUser(String encryptedData, String sessionKey, String iv) {
    // 被加密的数据
    byte[] dataByte = Base64Utils.decodeFromString(encryptedData);
    // 加密秘钥
    byte[] keyByte = Base64Utils.decodeFromString(sessionKey);
    // 偏移量
    byte[] ivByte = Base64Utils.decodeFromString(iv);
    try {
        // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要
        int base = 16;
        if (keyByte.length % base != 0) {
            int groups = keyByte.length / base + 1;
            byte[] temp = new byte[groups * base];
            Arrays.fill(temp, (byte) 0);
            System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
            keyByte = temp;
        }

        // 初始化
        Security.addProvider(new BouncyCastleProvider());
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
        SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
        AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
        parameters.init(new IvParameterSpec(ivByte));
        cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
        byte[] resultByte = cipher.doFinal(dataByte);

        return objectMapper.readValue(new String(resultByte, StandardCharsets.UTF_8), ObjectNode.class);
    } catch (Exception e) {
        logger.error("用户信息解密失败:{}", e.getMessage());
    }
}
相关推荐
丁总学Java6 小时前
微信小程序,点击bindtap事件后,没有跳转到详情页,有可能是app.json中没有正确配置页面路径
微信小程序·小程序·json
mosen8687 小时前
Uniapp去除顶部导航栏-小程序、H5、APP适用
vue.js·微信小程序·小程序·uni-app·uniapp
qq22951165028 小时前
微信小程序的汽车维修预约管理系统
微信小程序·小程序·汽车
小飞哥liac18 小时前
微信小程序的组件
微信小程序
stormjun19 小时前
Java基于微信小程序的私家车位共享系统(附源码,文档)
java·微信小程序·共享停车位·私家车共享停车位小程序·停车位共享
Bessie2341 天前
微信小程序eval无法使用的替代方案
微信小程序·小程序·uni-app
shenweihong1 天前
javascript实现md5算法(支持微信小程序),可分多次计算
javascript·算法·微信小程序
1 天前
微信小程序运营日记(第四天)
微信小程序·小程序
qq22951165021 天前
小程序Android系统 校园二手物品交换平台APP
微信小程序·uni-app
一只不会编程的猫2 天前
微信小程序配置
微信小程序·小程序