三步实现微信小程序登录

三步实现微信小程序登录

一、登录流程:

上面这个是微信官方给出的。在通过 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());
    }
}
相关推荐
FinClip2 小时前
微信AI小程序“亿元计划”来了!你的APP如何一键接入,抢先变现?
前端·微信小程序·app
计算机毕设指导66 小时前
基于微信小程序的考研资源共享系统【源码文末联系】
java·spring boot·后端·考研·微信小程序·小程序·maven
沉默-_-7 小时前
从小程序前端到Spring后端:新手上路必须理清的核心概念图
java·前端·后端·spring·微信小程序
week_泽7 小时前
百战商城商品数据云函数化改造总结_百战_3
数据库·笔记·微信小程序·小程序
『 时光荏苒 』8 小时前
微信小程序we分析如何采集webview的体验信息
微信小程序·小程序·webview·we分析
百锦再8 小时前
Vue大屏开发全流程及技术细节详解
前端·javascript·vue.js·微信小程序·小程序·架构·ecmascript
项目題供诗9 小时前
微信小程序黑马优购(项目)(十五)
微信小程序·小程序
云起SAAS9 小时前
婚礼邀请函请柬请帖制作生成抖音快手微信小程序看广告流量主开源
微信小程序·小程序·ai编程·看广告变现轻·婚礼邀请函
毕设源码-邱学长10 小时前
【开题答辩全过程】以 旅游信息系统为例,包含答辩的问题和答案
学习·微信小程序·小程序
计算机毕设指导610 小时前
基于微信小程序的直播带货商品数据分析系统【源码文末联系】
java·spring boot·微信小程序·小程序·tomcat·maven·intellij-idea