必备知识:小程序登录流程,springboot。
话不多说,直接上代码,具体问题在代码注释中给出
首先是小程序的代码:注意wx.login和wx.getUserInfo的先后
wx.login({
success: function(res){
wx.request({
url: 'http://localhost:8083/supermarket/login',
header: {
'Content-Type': 'application/x-www-form-urlencoded'
},
method: 'POST',
data: {
code: res.code,
},
success:function(res){
let resJson = JSON.parse(res.data.results);
let session_key = resJson.session_key;
wx.getSetting({
success: res => {
if (res.authSetting['scope.userInfo']) {
// 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
wx.getUserInfo({
success: function (msg) {
console.log(msg)
wx.request({
url: 'http://localhost:8083/supermarket/decrypt',
header: {
'Content-Type': 'application/x-www-form-urlencoded'
},
method: 'POST',
data: {
encryptedData: msg.encryptedData,
iv: msg.iv,
signature: msg.signature,
session_key: resJson.session_key
},
success: function (res) {
that.globalData.userInfo = JSON.parse(res.data.userInfo);
}
})
}
})
} else {
wx.reLaunch({
url: '/pages/main/main',
})
}
}
})
}
})
}
})
下面是Java解密代码:注意返回的的是String
//获取session_key的工具类
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
public class SendGetReq {
public static String sendGetReq(String url){
String result = "";
BufferedReader in = null;
try {
String urlNameString = url;
URL realUrl = new URL(urlNameString);
//打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
//设置通用的属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
//建立实际的连接
connection.connect();
//获取所有响应头字段
Map<String, List<String>> map = connection.getHeaderFields();
//定义BufferedReader输入流来读取URL响应
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
}catch (Exception e){
System.out.println("请求出现异常:"+e);
e.printStackTrace();
}finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
}
获取session_key:注意配置自己的appid和appsecret
import com.imooc.demo.util.SendGetReq;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
public class LoginController {
private static final String appsecret = "";
private static final String appid = "";
@RequestMapping(value = "/login", method = {RequestMethod.GET, RequestMethod.POST})
public Map<String, String> login(@RequestParam(value = "code") String code) {
String url = "https://api.weixin.qq.com/sns/jscode2session?appid=" + appid + "&secret=" + appsecret
+ "&js_code=" + code + "&grant_type=authorization_code";
String results = SendGetReq.sendGetReq(url);
System.out.println(results);
Map<String, String> map = new HashMap<>();
map.put("results", results);
return map;
}
}
下面上三个解密相关的类:
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
public class AES {
public static boolean initialized = false;
/**
* AES解密
*
* @param content
* 密文
* @return
* @throws InvalidAlgorithmParameterException
* @throws NoSuchProviderException
*/
public byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException {
initialize();
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
Key sKeySpec = new SecretKeySpec(keyByte, "AES");
cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化
byte[] result = cipher.doFinal(content);
return result;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public static void initialize() {
if (initialized)
return;
Security.addProvider(new BouncyCastleProvider());
initialized = true;
}
// 生成iv
public static AlgorithmParameters generateIV(byte[] iv) throws Exception {
AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
params.init(new IvParameterSpec(iv));
return params;
}
}
import java.nio.charset.Charset;
import java.util.Arrays;
public class WxPKCS7Encoder {
private static final Charset CHARSET = Charset.forName("utf-8");
private static final int BLOCK_SIZE = 32;
/**
* 获得对明文进行补位填充的字节.
*
* @param count
* 需要进行填充补位操作的明文字节个数
* @return 补齐用的字节数组
*/
public static byte[] encode(int count) {
// 计算需要填充的位数
int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
if (amountToPad == 0) {
amountToPad = BLOCK_SIZE;
}
// 获得补位所用的字符
char padChr = chr(amountToPad);
String tmp = new String();
for (int index = 0; index < amountToPad; index++) {
tmp += padChr;
}
return tmp.getBytes(CHARSET);
}
/**
* 删除解密后明文的补位字符
*
* @param decrypted
* 解密后的明文
* @return 删除补位字符后的明文
*/
public static byte[] decode(byte[] decrypted) {
int pad = decrypted[decrypted.length - 1];
if (pad < 1 || pad > 32) {
pad = 0;
}
return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
}
/**
* 将数字转化成ASCII码对应的字符,用于对明文进行补码
*
* @param a
* 需要转化的数字
* @return 转化得到的字符
*/
public static char chr(int a) {
byte target = (byte) (a & 0xFF);
return (char) target;
}
}
import net.sf.json.JSONObject;
import org.apache.commons.codec.binary.Base64;
public class WXCoreUtil {
private static final String WATERMARK = "watermark";
private static final String APPID = "appid";
/**
* 解密数据
* @return
* @throws Exception
*/
public static String decrypt(String appId, String encryptedData, String sessionKey, String iv){
String result = "";
try {
AES aes = new AES();
byte[] resultByte = aes.decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv));
if(null != resultByte && resultByte.length > 0){
result = new String(WxPKCS7Encoder.decode(resultByte));
JSONObject jsonObject = JSONObject.fromObject(result);
String decryptAppid = jsonObject.getJSONObject(WATERMARK).getString(APPID);
if(!appId.equals(decryptAppid)){
result = "";
}
}
} catch (Exception e) {
result = "";
e.printStackTrace();
}
return result;
}
public static void main(String[] args) throws Exception{
String appId = "wx0af48bd5a1edd0ff";
String encryptedData = "Gvb0SvE8wECRgL+z4RjqPItGeqJWHmRwY0lIIgxOBdzWU5fSiHCUcJ72tY6Mu9J3YxALaQXsd6hyDZoh0lY3fB2iC+isVgSKn0EP9S42KlJFy59rJn57vJGIwc9RJIiBp7ENArpg0XCPBIPvD3thUbNgI5Efhsx3XmIeXAVb/q5fsukZ8/p4UOt3Kh8EFFR2eK15zeknD5A98x6GFkDjuXszCFV+d0tQqksE9Lf/hw2RxyH46yTSYvivqe4uTEpWSVGj0NGFFp+r+EQLIQUE24FzxfZvC1ufSKBp8l83814+k2FiYnmvrV/jxK1R4D2U+c+pcEjPbG4ePV0x73YTUGjDnTalGm8M4riooaavSh5p+Tjm6UtNc7UxwIn1GW7KG8euqm6Um6gxS32361M5kDfGB/ilPJKexT8ySBIqvlr4pT7EQtit5wg7Y4SoMwftTvjKnYYoOntX3ELy70g2Raj+U2dA75lO8fgdT2LzGcs=";
String sessionKey = "NObptm58tmMQEJZREqKmfw==";
String iv = "ZKZ+H+Qhe+Y9tcnIDU/sYg==";
System.out.println(decrypt(appId, encryptedData, sessionKey, iv));
}
}
最后是解密的controller:
import com.imooc.demo.util.WXCoreUtil;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class DecryptUserInfo {
private static final String appid = "wx0af48bd5a1edd0ff";
@RequestMapping(value = "/decrypt", method = {RequestMethod.GET, RequestMethod.POST})
public Map<String, String> getUserInfo(@RequestParam(value = "encryptedData") String encryptedData,
@RequestParam(value = "iv") String iv,
@RequestParam(value = "signature") String signature,
@RequestParam(value = "session_key") String session_key) {
System.out.println(session_key + "--" + encryptedData + "--" + iv + "--" + signature);
String userInfo = WXCoreUtil.decrypt(appid, encryptedData, session_key, iv);
System.out.println(userInfo);
HashMap<String, String> map = new HashMap<>();
map.put("userInfo", userInfo);
return map;
}
}
打完收工。