https://www.cnblogs.com/dw3306/p/13577488.html
文章目录
- 系列文章目录
- 一、需要用到的依赖包
- 二、小程序登录获取用户信息流程
- 三、参数接受DTO
- 四、后端发请求的util工具方法
- 五、登录的接口
一、需要用到的依赖包
二、小程序登录获取用户信息流程org.projectlombok lombok cn.hutool hutool-all 5.4.0 org.bouncycastle bcprov-jdk15on 1.70
- 前端请求wx.login()方法获取jscode传给后端;
- 后端通过参数jscode、参数appid、参数appsecret请求接口auth.code2Session获取session_key和openid;(用来解密)
- 前端请求 wx.getUserInfo()方法获取用户的信息,传给后端;
- 后端解密后,存储用户的信息,然后自定义登录状态返回给给前端;
- 前端发起业务请求时,携带自定义登录状态。
总的来说:后端只是把前端拿到的加密的用户信息进行解密操作,再自定义登录状态返回给前端。
三、参数接受DTO
@Data
public class WeChatUserInfo {
// 小程序返回的code
private String jscode;
// 不敏感的用户数据(不包括敏感信息的原始数据字符串,用于计算签名)
private String rawData;
// 签名(使用 sha1( rawData + sessionkey ) 得到字符串,用于校验用户信息)
private String signature;
// 加密数据(包括敏感数据在内的完整用户信息的加密数据)
private String encryptedData;
// 加密密钥(加密算法的初始向量)
private String iv;
}
四、后端发请求的util工具方法
public class WeChatUtil {
public static JSONObject getSessionByCode(String jscode) {
// jscode是前端请求wx.login()方法获取的code;不是getPhoneNumber接口获取的code
// wx.login()方法,需要最先调用,否则可能会报错:pad block corrupted,获取不到解密的信息
String baseUrl = "https://api.weixin.qq.com/sns/jscode2session";
HashMap requestParam = new HashMap<>();
// 小程序 appId
requestParam.put("appid", "");
// 小程序 appSecret
requestParam.put("secret", "");
// 登录时获取的 code(小程序端返回的code)
requestParam.put("js_code", jscode);
// 默认参数,填“authorization_code”
requestParam.put("grant_type", "authorization_code");
// 发送post请求读取调用微信接口获取openid用户唯一标识
String result = HttpUtil.get(baseUrl, requestParam);
return JSONUtil.parseObj(result);
}
public static JSONObject getUserInfo(String encryptData, String sessionKey, String iv) {
// 解密:被加密的数据
byte[] dataByte = Base64.decode(encryptData);
// 解密:加密密钥
byte[] keyByte = Base64.decode(sessionKey);
// 解密:偏移量
byte[] ivByte = Base64.decode(iv);
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());
KeyGenerator.getInstance("AES").init(128);
// 生成iv
AlgorithmParameters iv1 = AlgorithmParameters.getInstance("AES");
iv1.init(new IvParameterSpec(ivByte));
// 生成解密
SecretKeySpec secretKeySpec = new SecretKeySpec(keyByte, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv1);// 设置为解密模式
byte[] decryptByte = cipher.doFinal(dataByte);
if (null != decryptByte && decryptByte.length > 0) {
String result = new String(decryptByte, "UTF-8");
return JSONUtil.parseObj(result);
}
} catch (Exception e) {
e.printStackTrace();
}
五、登录的接口
@RestController
@RequestMapping("/login")
public class WeChatUserLoginController {
@PostMapping
public String userLogin(@RequestBody WeChatUserInfo weChatUserInfo) {
// 1.请求微信接口服务,获取openid、sessionKey
JSONObject session = WeChatUtil.getSessionByCode(weChatUserInfo.getJscode());
// 2.接收微信接口服务返回的参数:{"session_key":"xxx","openid":"xxx"}
String openid = session.get("openid", String.class);
String sessionKey = session.get("session_key", String.class);
// 3.接收前端传来的用户不敏感信息
JSONObject rawDataJson = JSONUtil.parseObj(weChatUserInfo.getRawData());
String nickName = rawDataJson.get("nickName", String.class);
String avatarUrl = rawDataJson.get("avatarUrl", String.class);
String gender = rawDataJson.get("gender", String.class);
String province = rawDataJson.get("province", String.class);
String city = rawDataJson.get("city", String.class);
String country = rawDataJson.get("country", String.class);
// 4.解密获取被加密的数据 encrypteData(比rowData多了appid和openid)
JSONObject userInfo = WeChatUtil.getUserInfo(weChatUserInfo.getEncryptedData(), sessionKey, weChatUserInfo.getIv());
// 5.根据需求完成自己的业务(解析json对象获取数据)
// 6.uuid生成唯一key,用于维护微信小程序用户与服务端的会话(或者生成Token)
String skey = UUID.randomUUID().toString();
// 7.返回需要的数据给前端
return "";
}
}



