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>
















