1.修改 appId、secret 为自己的
package com.rongtong.modules.app.controller;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.rongtong.common.exception.RRException;
import lombok.Data;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.util.Arrays;
@RestController
public class WxLoginController {
// 小程序 appId
private final String appid = "wx75c9572*********";
// 小程序 appSecret
private final String secret = "57fc7766188f86af2e285**********";
// 算法名称
static final String KEY_ALGORITHM = "AES";
// 加解密算法/模式/填充方式
static final String algorithmStr = "AES/CBC/PKCS7Padding";
private static Key key;
private static Cipher cipher;
@Data
public static class WxLoginVo {
//公众号或小程序授权cod
private String code;
//包括敏感数据在内的完整用户信息的加密数据
private String encryptedData;
//加密算法的初始向量
private String iv;
}
@Data
public static class WxClient {
// 用户id 会员存在则返回
private Integer cid;
// 用户唯一标识
private String openId;
// 用户昵称
private String nickName;
// 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
private Integer gender;
// 用户头像
private String avatarUrl;
// 用户在开放平台的唯一标识符,若当前小程序已绑定到微信开放平台账号下会返回,详见 UnionID 机制说明。
private String unionid;
// 会话密钥
private String sessionKey;
}
/**
* 小程序登录
*/
@PostMapping("/wx/login")
public void wxLogin(@RequestBody WxLoginVo vo) {
String json = this.codeSession(vo.getCode());
WxClient client = JSON.parseObject(json, WxClient.class);
String openId = client.getOpenId();
System.out.println(openId);
String unionid = client.getUnionid();
System.out.println(unionid);
// 用户信息获取不到头像昵称了
// https://developers.weixin.qq.com/community/develop/doc/00022c683e8a80b29bed2142b56c01
WxClient program = this.getProgram(client.getSessionKey(), vo.getEncryptedData(), vo.getIv());
System.out.println(program);
}
private String codeSession(String code) {
String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + secret + "&js_code=" + code + "&grant_type=authorization_code";
String result = HttpUtil.get(url);
JSONObject object = JSONObject.parseObject(result);
return object.toString();
}
/**
* 获取小程序用户对象
*
* @param sessionkey
* @param encryptedData
* @param iv
* @return
*/
public WxClient getProgram(String sessionkey, String encryptedData, String iv) {
String result = getStr(encryptedData, sessionkey, iv);
WxClient client = JSON.parseObject(result, WxClient.class);
return client;
}
private static String getStr(String encryptedData, String keys, String iv) {
byte[] data = decrypt(encryptedData, keys, iv);
String dataStr = "";
try {
dataStr = new String(data, "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw new RRException("授权失败,请重新授权");
}
return dataStr;
}
/**
* 解密方法
*
* @param encryptedDataStr 要解密的字符串
* @param keyBytesStr 解密密钥
* @return
*/
public static byte[] decrypt(String encryptedDataStr, String keyBytesStr, String ivStr) {
byte[] encryptedText = null;
byte[] encryptedData = null;
byte[] sessionkey = null;
byte[] iv = null;
try {
sessionkey = Base64.decodeBase64(keyBytesStr);
encryptedData = Base64.decodeBase64(encryptedDataStr);
iv = Base64.decodeBase64(ivStr);
init(sessionkey);
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
encryptedText = cipher.doFinal(encryptedData);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new RRException("授权失败,请重新授权");
}
return encryptedText;
}
public static void init(byte[] keyBytes) {
// 如果密钥不足16位,那么就补足. 这个if 中的内容很重要
int base = 16;
if (keyBytes.length % base != 0) {
int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0);
byte[] temp = new byte[groups * base];
Arrays.fill(temp, (byte) 0);
System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length);
keyBytes = temp;
}
// 初始化
Security.addProvider(new BouncyCastleProvider());
// 转化成JAVA的密钥格式
key = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
try {
// 初始化cipher
cipher = Cipher.getInstance(algorithmStr);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}