微信小程序获取手机号,后端JAVA解密流程代码
作者:崔笑颜 发布时间:2023-11-29 07:57:26
标签:Java,微信小程序,获取手机号
小程序获取手机号,后端JAVA解密流程代码
微信官方文档获取手机号流程地址,先看下最好方便理解下面步骤
实现思路,步骤如下
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 解密出手机号
代码如下:
下面工具类很全,放心代码必须全,良心教程。
业务代码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:失败");
}
}
工具类代码如下
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;
}
}
来源:https://cloud.tencent.com/developer/article/1663626


猜你喜欢
- 1、Pull概述Android系统中和创建XML相关的包为org.xmlpull.v1,在这个包中不仅提供了用于创建XML的 X
- 运用Java编写代码将一个大文件切割成指定大小的小文件思路:对已知文件进行切割操作 –> 得到多个碎片文件使用:1、 1个字节输入流
- java使用stream实现list中对象属性的合并:根据两个List中的某个相同字段合并成一条List,包含两个List中的字段一、前言为
- 通过自定义注解的方式(如:@SysLog(obj = "操作对象", text = "操作内容"),
- 前言static静态的,不变的,在某个类中只有一个,不会因实例化对象的不同而不同。static可以修饰类、字段、属性、方法等。如一个方法前加
- 引言Object类是所有类、数组的父类,位于java.lang 包下也就是说,Java允许把所有任何类型的对象赋给Object类型的变量。当
- 背景:使用Idea编辑器一. SpringBoot项目打war包步骤:在pom.xml文件中的<build>标签,使用<f
- 何谓函数式编程相信大家在实际的开发中,很多情况下完成一个功能都需要借助多个类,那么我们这里的基本单元就是类。而函数式编程则更加细化,致使我们
- 在文件夹中,我们经常有类似s_1.txt、s_2.txt、s_10.txt、s_11.txt这样的命名方式,我们期望的排序方式是s_1.tx
- 跨域问题,其实百度上面有一堆的解决方案针对普通的情况其实百度上面的方案都是可行的。我这里主要介绍2种情况。当然我这里的配置都是基于网关的,而
- 实例如下:#region 自定义变量 int currentCol = -1; bool sort; #
- 推荐教程IntelliJ IDEA 2020最新激活码(亲测有效,可激活至 2089 年)最新idea2021注册码永久激活(激活到2100
- 以最终客户的角度来看,JAR文件就是一种封装,他们不需要知道jar文件中有多少个.class文件,每个文件中的功能与作用,同样可以得到他们希
- Windows 服务(即,以前的 NT 服务)使您能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序。这些服务可以在计
- 整理文档,搜刮出一个java后台接受app上传的图片的示例代码,稍微整理精简一下做下分享package com.sujinabo.file;
- MyEclipse配置IDEA配置Tomcat环境IDEA:2020.2Tomcat:apache-tomcat-9.0.38创建Web项目
- 今天给大家带来的是一个 SpringBoot导入导出数据首先我们先创建项目 注意:创建SpringBoot项目时一定要联网不然会报错项目创建
- 在使用spring boot进行打包的时候出现了一些问题,不是说找不到主类,就是说spring初始化时有些类没有加载。下面介绍一下如何解决。
- RetrofitA type-safe HTTP client for Android and Java 适用于Java和Android的安
- IntelliJ IDEA 2022.2为远程开发功能带来了多项质量改进,使其更美观、更稳定。从 v2022.2 开始,IntelliJ I