uniapp+java 获取用户手机号

首先你的appid不能是个体,具体可以参照微信官方文档

  • 实现思路很简单
  1. 前端使用button的开放属性获取当前登录code和偏移量(iv)加密数据(encryptedData)
  2. 将获取到的数据回传到后台进行解密即可
  • 前端html
<button class="wechatlogin" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber"   type="primary">微信登录</button>
//js
/* 获取用户手机 */
			async getPhoneNumber(e) {
				if (this.code.length == 0) {
					this.getCode();
				}
				const res = await this.httpRequest({ //这是我自己封装的请求方法
					url: '/user/getPhoneNumber',  //后端解析电话号码地址
					method: 'POST',
					data: { //解密电话需要的数据
						'iv': e.detail.iv,   
						'encryptedData': e.detail.encryptedData,
						'code': this.code
					}
				})
				console.log(res.data);
				if(res.data.success){
					uni.showToast({
						title:'登录成功',
						icon:'success'
					});
					uni.setStorageSync('token',res.data.data.token) 
					setTimeout(()=>{
						uni.switchTab({
							url:'../main/main'
						})
					},1000)
				}else{
					uni.showToast({
						title:'微信登录失败。请切换到手动登录',
						icon:'none'
					});
				}
			}
  • 后端,我用的是java实现
  1. 为了方便,我自己创建了一个bean用来接收前端传回的数据
  2. 根据前端传回来的数据去微信那边获取session_key和oppenid,当然对我们解密电话号码来说只有session_key是有用的
  3. 然后就是解密了,下面直接贴代码
  • 后端代码
  • javabean
//首先创建了一个bean来接收前端传回的数据
@Data
public class WeixinGetPhone {
    private String iv;
    private String code;
    private String encryptedData;
}
  • 工具类(用于发起get请求,获取session_key和oppenId)
public class WeiXinGetSessionKeyUtil {

    private static final String appid = "XXX";
    private static final String AppSecret = "XXX";


    public static String getSessionKey(String code) {
        StringBuilder result = new StringBuilder();
        String GEt_URL = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + AppSecret + "&js_code=" + code + "&grant_type=authorization_code";
        BufferedReader bufferedReader = null;
        try {
            URL url = new URL(GEt_URL);
            /*打开url之间的链接*/
            URLConnection urlConnection = url.openConnection();
            /*设置通用的请求属性*/
            urlConnection.setRequestProperty("accept", "*/*");
            urlConnection.setRequestProperty("connection", "Keep-Alive");
            urlConnection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            /*建立实际的链接*/
            urlConnection.connect();
            /*获取响应头*/
            Map<String, List<String>> map = urlConnection.getHeaderFields();
            for (String key : map.keySet()) {
                System.out.println(key + "======>" + map.get(key));
            }
            //定义bufferReader输入流;来读取url响应
            bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                result.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("发送get请求出现异常" + e);
        } finally {
            try {
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println(result.toString()); 
        //解密只需要用session_key,所以我这里直接返回session_key
        //json解析工具用的是阿里的fastjson
        JSONObject jsonObject = JSON.parseObject(result.toString());
        return jsonObject.getString("session_key");
    }
}
  • 根据上一步拿到的session_key来解密手机号
/*获取用户手机号码*/
//这里面解密的代码我也是网上找的,后来准备贴一下原文链接,但是我清除了浏览器缓存之后找不到了,在这里就衷心的感谢哪位不知名的大神
    public String getPhoneNumber(String sessionKey, WeixinGetPhone weixinGetPhone) {
        String result = "";
        byte[] dataByte = new byte[0];
        byte[] keyByte = new byte[0];
        byte[] ivByte = new byte[0];
        try {
            /,**,记得替换特殊字符。。。。
            //这个替换字符特别重要,不写就报错。
            String replace = URLEncoder.encode(weixinGetPhone.getEncryptedData(), "UTF-8").replace("%3D", "=").replace("%2F", "/").replace("%2B", "+");
            //我这里不知道为什么必须这样使用base64其他小伙伴如果报错的话把前面的包名去掉试试
            dataByte = org.apache.commons.codec.binary.Base64.decodeBase64(replace);
            String replace2 = URLEncoder.encode(sessionKey, "UTF-8").replace("%3D", "=").replace("%2F", "/").replace("%2B", "+");
            keyByte = org.apache.commons.codec.binary.Base64.decodeBase64(replace2);
            String replace1 = URLEncoder.encode(weixinGetPhone.getIv(), "UTF-8").replace("%3D", "=").replace("%2F", "/").replace("%2B", "+");
            ivByte = org.apache.commons.codec.binary.Base64.decodeBase64(replace1);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        try {
            // 如果密钥不足16位,那么就补足. 这个if 中的内容很重要
            int base = 16;
            if (keyByte.length % base != 0) {
                int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
                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);
            if (null != resultByte && resultByte.length > 0) {
                String s = resultByte.toString();
                result = new String(resultByte, "UTF-8");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //result就是解密后的数据,我这里只需要电话号码,所以进行了数据处理
        System.out.println("result" + result);
        JSONObject jsonObject = JSONObject.parseObject(result);
        return jsonObject.getString("phoneNumber");

    }
  • controller里面的方法
@PostMapping("/getPhoneNumber")
    @ApiOperation("用户授权后获取用户手机号")
//返回类型R为自己定义的全局返回对象
    public R getPhoneNumber(@RequestBody WeixinGetPhone weixinGetPhone) {
        //WeiXinGetSessionKeyUtil,由于发起get请求并解析数据得到session_key的代码会有点多,所以我抽成了一个工具类,上面有贴这个工具类
        //获取解密手机号需要的sessionkey
      String sessionKey = WeiXinGetSessionKeyUtil.getSessionKey(weixinGetPhone.getCode());
        //根据session_key和偏移量(iv)解密前端传回的加密数据
        //解密方法我也抽成了一个单独方法,上面也贴了
        String phoneNumber = getPhoneNumber(sessionKey, weixinGetPhone);
        System.out.println("用户手机号:"+phoneNumber);
        ...
    }
  • 到此获取用户手机号也就算是收工了
  • 附使用到的jar包
<dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.10</version>
    </dependency>
      <dependency>
        <groupId>org.codehaus.xfire</groupId>
        <artifactId>xfire-core</artifactId>
        <version>1.2.6</version>
    </dependency>
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk16</artifactId>
        <version>1.46</version>
    </dependency>
        <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.18</version>
    </dependency>
        <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.73</version>
    </dependency>