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

新版:前端要授权两次,一次获取用户信息授权码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 the
        Security.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;
    @Autowired
    private CuCustomerService cuCustomerService;
    @Autowired
    private 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 "";
    }

    @Override
    public 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 {
//        写入微信openid
            if (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);
        //防止用户多端登录,产生多个token
        String 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失效,从而使得后端解密失败。

微信小程序文档

  • 6
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
要在uniapp获取微信用户的手机号,需要进行以下步骤: 1. 首先在微信公众平台上创建一个小程序,获取小程序的AppID和AppSecret。 2. 在uniapp项目中安装微信开发工具插件,并在manifest.json文件中配置AppID和微信开发者工具的路径。 3. 在uniapp项目中使用wx.login()方法获取用户的登录凭证code。 4. 使用wx.request()方法向微信服务器发送请求,获取session_key和openid。 5. 使用session_key和encryptedData以及iv参数解密用户的手机号。 以下是一个示例代码: ```javascript // 获取用户的手机号 getPhoneNumber: function (e) { wx.login({ success: res => { wx.request({ url: 'https://api.weixin.qq.com/sns/jscode2session?appid=' + appid + '&secret=' + secret + '&js_code=' + res.code + '&grant_type=authorization_code', success: function (res) { // 获取session_key和openid var session_key = res.data.session_key; var openid = res.data.openid; // 解密用户的手机号 wx.request({ url: 'https://api.weixin.qq.com/wxa/getphonenumber?access_token=' + access_token, data: { session_key: session_key, encryptedData: e.detail.encryptedData, iv: e.detail.iv }, success: function (res) { // 获取用户的手机号 var phoneNumber = res.data.phoneNumber; console.log(phoneNumber); } }) } }) } }) } ``` 在这个示例代码中,我们首先使用wx.login()方法获取用户的登录凭证code,然后使用wx.request()方法向微信服务器发送请求,获取session_key和openid。接着,我们使用session_key、encryptedData和iv参数解密用户的手机号,最后获取到用户的手机号并打印到控制台上。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值