uniapp+java 获取用户手机号
首先你的appid不能是个体,具体可以参照微信官方文档
-
实现思路很简单
- 前端使用button的开放属性获取当前登录code和偏移量(iv)加密数据(encryptedData)
- 将获取到的数据回传到后台进行解密即可
-
前端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实现
- 为了方便,我自己创建了一个bean用来接收前端传回的数据
- 根据前端传回来的数据去微信那边获取session_key和oppenid,当然对我们解密电话号码来说只有session_key是有用的
- 然后就是解密了,下面直接贴代码
-
后端代码
- 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>