1.前端需先调用官方wx.login接口获取登录凭证code。
2.后端接收code 调用官方接口地址获取用户秘钥 sessionKey。
3.前端通过官方getPhoneNumber获取encryptedData,iv
4.前端通过参数**【encryptedData】 、【iv】 、【sessionKey】** 发送请求后端接口,解密用户手机号
小程序获取sessionkey详细接口文档
后端工作如下,
1 参数code 解密出sessionKey
{“session_key”:“eF9PAi5P7ZbSaQqkGzEY5g==”,“openid”:“otJ1I4zMSFGDtk7C33O_h6U3IRK8”}
2.参数sessionKey,iv,encryptedData 解密出手机号
代码如下:
下面工具类很全,放心代码必须全,良心教程。
1.业务代码Controller
上代码,上代码,上代码,上代码,上代码
package com.df.detection.controller;
import com.df.detection.base.entity.ResultBean;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import org.apache.commons.codec.binary.Base64;
import org.json.JSONException;
import org.springframework.web.bind.annotation.*;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import org.json.JSONObject;
/**
* @Author Songzhongjin
* @Date 2020/7/15 10:09
* @Version 1.0
*/
@Api(value = "小程序登录授权 Controller",tags = {"小程序登录授权接口"})
@RestController
@RequestMapping("/app")
public class APPController {
/**
* 微信小程序登录获取
* 获取session_key
* @param
* @return
*/
@ResponseBody
@PostMapping("/initWxLogin")
@ApiImplicitParams({
@ApiImplicitParam(name = "js_code", value = "登录时获取的code",paramType = "form", dataType = "string", required = true)
})
public ResultBeaninitWxLogin(@RequestParam(value = "js_code", required = true) String js_code) throws JSONException {
//测试数据code
// js_code = "081ZQ3f91fr9VM1HYdb91y93f91ZQ3fU";
//微信获取session_key接口地址
String wxLoginUrl = "https://api.weixin.qq.com/sns/jscode2session";
//接口参数
String param = "appid=小程序id&secret=小程序secret&js_code=" + js_code + "&grant_type=authorization_code";
//调用获取session_key接口 请求方式get
String jsonString = GetPostUntil.sendGet(wxLoginUrl, param);
System.out.println(jsonString);
//因为json字符串是大括号包围,所以用JSONObject解析
JSONObject json = new JSONObject(jsonString);
//json解析session_key值
String session_key = json.getString("session_key");
System.out.println("session_key:" + session_key);
//返回给前端
return ResultBean.success("session_key",session_key);
}
/**
* 解密小程序用户敏感数据
*
* @param encryptedData 明文
* @param iv 加密算法的初始向量
* @param sessionKey 用户秘钥
* @return
*/
@ResponseBody
@PostMapping(value = "/decodeUserInfo")
@ApiImplicitParams({
@ApiImplicitParam(name = "encryptedData", value = "包括敏感数据在内的完整用户信息的加密数据",paramType = "form", dataType = "string", required = true),
@ApiImplicitParam(name = "iv", value = "加密算法的初始向量",paramType = "form", dataType = "string", required = true),
@ApiImplicitParam(name = "sessionKey", value = "用户秘钥",paramType = "form", dataType = "string", required = true)
})
public ResultBean decodeUserInfo(@RequestParam(required = true, value = "encryptedData") String encryptedData,
@RequestParam(required = true, value = "iv") String iv,
@RequestParam(required = true, value = "sessionKey") String sessionKey
) throws UnsupportedEncodingException, InvalidAlgorithmParameterException, JSONException {
//AESUtils微信获取手机号解密工具类
AESUtils aes = new AESUtils();
//调用AESUtils工具类decrypt方法解密获取json串
byte[] resultByte = aes.decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv));
//判断返回参数是否为空
if (null != resultByte && resultByte.length > 0) {
String jsons = new String(resultByte, "UTF-8");
System.out.println(jsons);
JSONObject json = new JSONObject(jsons);
//json解析phoneNumber值
String phoneNumber = json.getString("phoneNumber");
System.out.println("phoneNumber:" + phoneNumber);
return ResultBean.success("手机号", phoneNumber);
}
return ResultBean.error(500,"session_key:失败");
}
}
2.工具类代码如下
get 请求工具类
package com.df.detection.controller;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.Map;
/**
* @Author Songzhongjin
* @Date 2020/7/15 10:37
* @Version 1.0
*/
public class GetPostUntil {
/**
* 向指定URL发送GET方法的请求
*
* @param url
* 发送请求的URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return URL 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param) {
String result = "";
BufferedReader in = null;
try {
String urlNameString = url + "?" + param;
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();
// 遍历所有的响应头字段
for (String key : map.keySet()) {
System.out.println(key + "--->" + map.get(key));
}
// 定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url
* 发送请求的 URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!"+e);
e.printStackTrace();
}
//使用finally块来关闭输出流、输入流
finally{
try{
if(out!=null){
out.close();
}
if(in!=null){
in.close();
}
}
catch(IOException ex){
ex.printStackTrace();
}
}
return result;
}
}
AESUtils工具类 解密手机号
package com.df.detection.controller;
import org.apache.tomcat.util.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
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 javax.xml.transform.Result;
import java.security.*;
/**
* @Author Songzhongjin
* @Date 2020/7/15 11:46
* @Version 1.0
*/
public class AESUtils {
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;
}
}
接口返回对象ResultBean定义工具类 防止有些朋友发现没有这个类
package com.df.detection.base.entity;
import io.swagger.annotations.ApiModelProperty;
/**
* @author Liu Yaoguang
* @Classname aaa
* @Description
* @Date 2019/12/06 09:22
*/
public class ResultBean<T> {
@ApiModelProperty(value = "返回码",dataType = "int")
private int code;
@ApiModelProperty(value = "返回描述信息",dataType = "string")
private String message;
@ApiModelProperty(value = "返回数据")
private T data;
@ApiModelProperty(value = "口令",dataType = "string")
private String token;
private ResultBean() {
}
public static ResultBean error(int code, String message) {
ResultBean resultBean = new ResultBean();
resultBean.setCode(code);
resultBean.setMessage(message);
return resultBean;
}
public static<T> ResultBean error(int code, String message,T data) {
ResultBean resultBean = new ResultBean();
resultBean.setCode(code);
resultBean.setMessage(message);
resultBean.setData(data);
return resultBean;
}
public static ResultBean success(String message) {
ResultBean resultBean = new ResultBean();
resultBean.setCode(200);
resultBean.setMessage(message);
return resultBean;
}
public static<T> ResultBean success(String message,T data) {
ResultBean resultBean = new ResultBean();
resultBean.setCode(200);
resultBean.setMessage(message);
resultBean.setData(data);
return resultBean;
}
public static ResultBean success(String message,Object data,String token) {
ResultBean resultBean = new ResultBean();
resultBean.setCode(200);
resultBean.setMessage(message);
resultBean.setData(data);
resultBean.setToken(token);
return resultBean;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
代码能跑的通,记得点个赞。