新版:前端要授权两次,一次获取用户信息授权码code,另外一次获取用户手机授权码code,全部传给后端。后端通过用户信息授权码获取openid,通过手机授权码获取手机号码。老版:前端传给后端授权码code和用户手机授权回调 里的iv和encryptedData给后端,后端通过code获取openid和sessionKey,然后他用sessionKey和iv解密encryptedData获取手机号。最后通过手机号进行绑定用户,然后通过登录验证返回给前端登录凭证token。

登录逻辑

新版

1.调用uni.login()获取code1

2.用户主动触发button按钮在回调getPhoneNumber获取code2

<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>Page({getPhoneNumber (e) {console.log(e.detail.code)}
})

3.后端拿到code1获取openid ,code2获取手机号码(代码在api里面)

老版

1.先在onshow()生命周期中获取code

2.用户主动触发button按钮在回调getPhoneNumber获取iv和encryptedData

<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber"></button>
Page({getPhoneNumber (e) {console.log(e.detail.errMsg)console.log(e.detail.iv)console.log(e.detail.encryptedData)}
})

3.后端拿到code、iv、encryptedData,然后code获取openid和sessionKey,然后通过sessionKey和iv解密encryptedData获取到手机号

获取得到的解密数据为以下 json 结构:{"phoneNumber": "13580006666","purePhoneNumber": "13580006666","countryCode": "86","watermark":{"appid":"APPID","timestamp": TIMESTAMP}
}

解密工具类

package hry.project.cdwjs.wxLogin;import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;/*** @author qyb* @version 1.0* @date 2023/3/13-9:38*/
public class WxDecryptUtills {public static boolean initialized = false;/*** Adds a provider to the next position available.*/public static void initialize() {if (initialized) return;// Construct a new provider.  This should only be required when// using runtime registration of the provider using theSecurity.addProvider(new BouncyCastleProvider());initialized = true;}// iv处理public static AlgorithmParameters generateIV(byte[] iv) throws Exception{AlgorithmParameters params = AlgorithmParameters.getInstance("AES");params.init(new IvParameterSpec(iv));return params;}/*** AES解密* @param content 密文* @param keyByte sessionKey* @param ivByte iv* @return 解密json数据*/public static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte)  {initialize();try {Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");Key sKeySpec = new SecretKeySpec(keyByte, "AES");// cipher 初始化cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));return cipher.doFinal(content);} catch (Exception e) {e.printStackTrace();}return null;}/*** 微信小程序用户信息解密* @param encryptedData 加密数据* @param sessionKey    会话密钥* @param iv            向量* @return {@link String}*/public static String decrypt(String encryptedData, String sessionKey, String iv){try {byte[] resultByte = decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv));if(null != resultByte && resultByte.length > 0){return new String(resultByte, StandardCharsets.UTF_8);}} catch (Exception e) {e.printStackTrace();}return null;}
}

api

package hry.project.cdwjs.wxLogin.impl;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import hry.bean.JsonResult;
import hry.business.cu.model.CuCustomer;
import hry.business.cu.service.CuCustomerService;
import hry.project.cdwjs.wxLogin.WxDecryptUtills;
import hry.project.cdwjs.wxLogin.WxLoginService;
import hry.project.cdwjs.wxLogin.WxLoginVo;
import hry.redis.RedisService;
import hry.security.jwt.JWTToken;
import hry.security.jwt.JWTUtil;
import hry.utils.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;import java.util.HashMap;/*** @author qyb* @version 1.0* @date 2023/3/9-17:38*/
@Service
@Slf4j
public class WxLoginServiceImpl implements WxLoginService {@Value("${wxLogin.appId}")private String appId;@Value("${wxLogin.appSecret}")private String appSecret;@Autowiredprivate CuCustomerService cuCustomerService;@Autowiredprivate RedisService redisService;/*** 获取accesstoken** @return*/private String getAccessToken() {String accessToken = "";String url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appId + "&secret=" + appSecret;try {String resultString = HttpUtils.get(url);log.info("获取微信accessToken:{}", resultString);if (StringUtils.isNotEmpty(resultString)) {JSONObject jsonObject = JSON.parseObject(resultString);accessToken = jsonObject.get("access_token").toString();} else {log.error("返回值为空,请检查请求报文或者请求地址是否正确");}} catch (Exception e) {e.printStackTrace();}return accessToken;}/*** 获取手机号*/private String getPhoneNumber(String code) {String phoneNumber = "";String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + getAccessToken();HashMap<String, String> params = new HashMap<>();params.put("code", code);try {String resultString = HttpUtils.postByQuery(url, params, null);log.info("获取微信手机号码:{}", resultString);if (StringUtils.isNotEmpty(resultString)) {JSONObject jsonObject = JSON.parseObject(resultString);JSONObject phone_info = jsonObject.getJSONObject("phone_info");phoneNumber = phone_info.getString("phoneNumber");} else {log.error("返回值为空,请检查请求报文或者请求地址是否正确");}} catch (Exception e) {e.printStackTrace();}return phoneNumber;}/*** 获取openId*/private String getOpenId(String code) {String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appId + "&secret=" + appSecret + "&js_code=" + code + "&grant_type=authorization_code";try {String resultString = HttpUtils.get(url);log.info("获取微信openId:{}", resultString);if (StringUtils.isNotEmpty(resultString)) {return resultString;} else {log.error("返回值为空,请检查请求报文或者请求地址是否正确");}} catch (Exception e) {e.printStackTrace();}return "";}@Overridepublic JsonResult loginByWx(WxLoginVo wxLoginVo) {String res = this.getOpenId(wxLoginVo.getUserInfoCode());JSONObject jsonObject = JSONObject.parseObject(res);String openId = jsonObject.getString("openid");String sessionKey = jsonObject.getString("session_key");if (StringUtils.isEmpty(openId)) {return new JsonResult().setMsg("未获取到openId,登录失败");}String data = WxDecryptUtills.decrypt(wxLoginVo.getEncryptData(), sessionKey, wxLoginVo.getIv());JSONObject jsonObject1 = JSONObject.parseObject(data);String phoneNumber =jsonObject1.getString("phoneNumber");if (StringUtils.isEmpty(phoneNumber)) {return new JsonResult().setMsg("未获取到手机号,登录失败");}CuCustomer cuCustomer = cuCustomerService.checkMobile(phoneNumber);if (cuCustomer == null) {
//            注册cuCustomer = cuCustomerService.regist3(openId, phoneNumber, wxLoginVo.getNickname(), wxLoginVo.getAvatar());} else {
//        写入微信openidif (StringUtils.isEmpty(cuCustomer.getWxOpenId())) {cuCustomer.setWxOpenId(openId);}cuCustomer.setWxAvatar(wxLoginVo.getAvatar());cuCustomerService.update(cuCustomer);}
//        登录String token = JWTUtil.sign(phoneNumber, JWTToken.SOURCE_PC, JWTToken.TYPE_CUSTOMER, cuCustomer.getPassword());redisService.save(JWTUtil.getCustomerRefreshTimeKey(token), JSON.toJSONString(cuCustomer), JWTUtil.REFRESH_TIME);redisService.save(JWTUtil.getCustomerUserKey(token), JSON.toJSONString(cuCustomer), JWTUtil.EXPIRE_TIME);//防止用户多端登录,产生多个tokenString oldTokenStr = redisService.get("LOGINCUCUSTOMER:" + cuCustomer.getId());if (StringUtils.isNotEmpty(oldTokenStr)) {JWTToken oldToken = new JWTToken(oldTokenStr);redisService.delete("JWT:token:" + oldToken.getSource() + ":" + oldToken.getType() + ":refreshTime:" + oldToken.getSignId());redisService.delete("JWT:token:" + oldToken.getSource() + ":" + oldToken.getType() + ":user:" + oldToken.getSignId());}redisService.save("LOGINCUCUSTOMER:" + cuCustomer.getId(), token);HashMap<String, Object> map = new HashMap<>();map.put("token", token);return new JsonResult().setSuccess(true).setObj(map);}
}

注意:老版调用过程中一定要先调用uni.login(),再去触发button获取手机号,不然会导致sessionKey失效,从而使得后端解密失败。

微信小程序文档

uniapp微信小程序授权登录并获取手机号相关推荐

  1. uniapp微信小程序授权登录和获取微信绑定的手机号码

    uniapp微信小程序授权登录和获取微信绑定的手机号码 弹出授权的弹框 <view class="weixinOk" @tap="getUserProfile&qu ...

  2. 微信小程序授权登录(获取手机号及用户信息)

    目录 1.开放平台绑定微信小程序 2.小程序AppID/AppSecret获取 3.获取授权信息 4.获取用户信息

  3. 微信小程序授权登录和获取手机号功能(详细)

    总结,新增获取用户手机号功能,里面用到了关于获取用户信息和用户手机号的功能,一开始写的时候发现我把两个按钮写在一个登录页面上,获取手机号逻辑是当用户点击授权之后跳转到首页,当点击拒绝弹窗提示,最后发现 ...

  4. uni-app 微信小程序授权登录

    文章目录 一.appID相关申请和配置 1. appid获取方式 2. appID配置 二.获取用户基础数据 2.1. 获取用户信息 2.2. 获取用户信息2 三.调用登录api 3.1. 登录api ...

  5. 微信小程序授权登录(含获取基本信息及绑定的手机号)

    1.授权获取微信个人信息 wx.getUserProfile({desc: '展示用户信息',success: (res) => {this.setData({nickName: res.use ...

  6. uniapp微信小程序授权登录流程(代码直接复制可用)

    1.写一个点击登录的按钮 <view @tap="login">一键登录</view> 2.写点击事件 login() {wx.getUserInfo({s ...

  7. SpringCloud 微信小程序授权登录 获取openId SessionKey【SpringCloud系列13】

    SpringCloud 大型系列课程正在制作中,欢迎大家关注与提意见. 自我提升方法推荐:神奇的早起 早上 5:00 -5:20 起床刷牙 5:30-6:00 晨练(跑步.跳绳.骑自行车.打球等等) ...

  8. 基于Uniapp+SpringBoot实现微信小程序授权登录

    手把手教你做微信小程序授权登录交互 一.uni.login请求临时code 二.uni.request向后台交换数据 三.源代码 前台:在GetUserInfo中添加接口 后台:SpringBoot后 ...

  9. 微信小程序授权登录+获取手机号

    微信小程序授权登录+获取手机号 一.官方文档背景: 小程序登录的链接: 微信小程序获取手机号的链接: 二.微信小程序授权登录+获取手机号 1.简单说明官方文档的操作:先授权登录后拿手机号 2.前端代码 ...

最新文章

  1. JavaScript 正则表达式的使用
  2. linux下两个进程可以同时打开同一个文件吗?返回的文件描述符一样吗?
  3. PAT甲级1025 PAT Ranking:[C++题解]排序、结构体、排名
  4. Apache——启动错误:[Cannot load modules/mod_actions.so into server]解决方案
  5. TCP/IP GUIDE
  6. kindeditor用法简单介绍(转)
  7. python 加密解密_python加密解密
  8. Java基本数据类型及所占字节大小
  9. ciscodk新科目——1Z1-807
  10. 关于F5 排错的简单介绍之一
  11. mysql 与QT的连接
  12. 添加图标_图标变化、小程序添加到桌面...微信电脑版这些功能更新!
  13. win11如何进行bug反馈 windows11进行bug反馈的步骤方法
  14. python的range和linspace
  15. 软件测试相关英文单词整理
  16. 区块链开源代码什么意思_区块链可以从开源中学到什么
  17. 股票因子扩展2(双神因子计算)——从零到实盘5
  18. latex插图\begin{minipage}强制左移\hspace命令
  19. unantu下的tmp文件夹_Ubuntu根目录下各文件夹的功能详细介绍
  20. Free Code Camp 练习总结(五) ——Introduction to the ES6 Challenges ES6基本用法和基础知识

热门文章

  1. mySQL清清除特殊格式
  2. c语言编写函数求回文数,C语言求回文数(详解版)
  3. 良精南方cms /inc/Check_Sql.asp SQL Injection Based On Cookie
  4. OpenEuler安装Kubernetes+KubeSphere教程
  5. 本地电脑文件共享服务器,服务器和电脑文件的共享
  6. 263海外邮箱服务器设置,263企业G邮局海外服务器
  7. 虚拟磁盘discard在qemu中的应用
  8. 五种知识图式的绘制方法(思维导图、概念图、知识图谱、语义网络、认知图)
  9. 最好的pdf转换成ppt转换器
  10. 智慧职教云答案在哪里找_智慧职教云答案在哪里找到,智慧职教计算机应用答案,智慧职教搜题软件答案在线查询的软件搜题答案神器...