第三方登入现在以及非常普遍了,所以在此记录微信登入的现实方式
看图
说明:
- 调用 wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。
- 调用 code2Session 接口,换取 用户唯一标识 OpenID 和 会话密钥 session_key。
之后开发者服务器可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份。
注意:
- 会话密钥
session_key
是对用户数据进行 加密签名 的密钥。为了应用自身的数据安全,开发者服务器不应该把会话密钥下发到小程序,也不应该对外提供这个密钥。 - 临时登录凭证 code 只能使用一次
具体代码
wx.login({
success(res) {
if (res.code) {
// 发起网络请求
wx.request({
url: 'https://test.com/onLogin',
data: {
code: res.code//将code传入的服务端
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
//获取到code
//Java代码
//appid,secret 保存在服务端
OkHttpClient client = new OkHttpClient();
Request okrequest = new Request.Builder()
.url("https://api.weixin.qq.com/sns/jscode2session?appid=" + WeiXinConfig.APP_ID + "&secret="+ WeiXinConfig.SECRET + "&js_code=" + request.getCode() + "&grant_type=authorization_code").get().addHeader("cache-control", "no-cache").build();
try {
Response response = client.newCall(okrequest).execute();
if (200 != response.code()) {
throw new BizException("获取微信用户信息失败");
}
String openkey = response.body().string();
JSONObject open = JSONObject.parseObject(openkey);
String openid = open.getString("openid");
if (StringUtils.isEmpty(openid)) {
throw new BizException("获取微信openid失败");
}
user = userExtendsMapper.selectUserByOpenId(openid);
userProfile.setUserId(user.getId());
String us = JSONObject.toJSON(userProfile).toString();
try {
createJWT = TokenUtil.createJWT(UUIDGenerator.getUUID(), us, Constant.JWT_TTL);
} catch (Exception e) {
throw new BizException("生成token失败");
}
//生产服务token,用于微信小程序与服务器交互
接下来就是采用session_key去获取手机号码了
需要将 <button>
组件 open-type
的值设置为 getPhoneNumber
,当用户点击并同意之后,可以通过 bindgetphonenumber
事件回调获取到微信服务器返回的加密数据, 然后在第三方服务端结合 session_key
以及 app_id
进行解密获取手机号。
Page({
getPhoneNumber(e) {
console.log(e.detail.errMsg)
console.log(e.detail.iv)
console.log(e.detail.encryptedData)
}
}
})
//Java服务器端代码 获取session-key code是前端调用login()方法获取到传入后台的
public static String getSeesionKey(String code) {
String sessionKey = null;
OkHttpClient client = new OkHttpClient();
Request okrequest = new Request.Builder()
.url("https://api.weixin.qq.com/sns/jscode2session?appid=" + WeiXinConfig.APP_ID + "&secret="+ WeiXinConfig.SECRET + "&js_code=" + code + "&grant_type=authorization_code").get().addHeader("cache-control", "no-cache").build();
Response response;
try {
response = client.newCall(okrequest).execute();
if (200 != response.code()) {
throw new BizException("获取微信用户信息失败");
}
String openkey = response.body().string();
JSONObject open = JSONObject.parseObject(openkey);
sessionKey = open.getString("session_key");
if (StringUtils.isEmpty(sessionKey)) {
throw new BizException("获取微信sessionKey失败");
}
} catch (IOException e) {
throw new BizException("获取微信sessionKey失败");
}
return sessionKey;
}
//解密方法
public static String decrypt(String encrypted, String session_key, String iv) throws Exception {
byte[] encrypData = Base64.decodeBase64(encrypted);
byte[] ivData = Base64.decodeBase64(iv);
byte[] sessionKey = Base64.decodeBase64(session_key);
// byte[] sessionKey = Base64.decodeBase64("Fn6r4IOiZJBXn4hQ0w==");
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivData);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec keySpec = new SecretKeySpec(sessionKey, "AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
// 解析解密后的字符串
return new String(cipher.doFinal(encrypData), "UTF-8");
}
//前台传入code,encrypted,iv
public String getPhone(GetPhoneRequestBody request) {
String seesionKey = AESDecodeUtils.getSeesionKey(request.getCode());
String decrypt;
try {
decrypt = AESDecodeUtils.decrypt(request.getEncrypted(), seesionKey, request.getIv());
} catch (Exception e) {
throw new BizException("解密失败");
}
//返回格式
//{
// "phoneNumber": "13580006666",
// "purePhoneNumber": "13580006666",
// "countryCode": "86",
// "watermark": {
// "appid": "APPID",
// "timestamp": TIMESTAMP
// }
JSONObject open = JSONObject.parseObject(decrypt);
String phoneNumber = open.getString("phoneNumber");
if (StringUtils.isEmpty(phoneNumber)) {
throw new BizException("获取微信手机号失败");
}
return phoneNumber;
}
最后返回phone给前端