小程序encryptedData
准备知识:
- Base64编解码
- AES算法、填充模式、偏移向量
- session_key会话密钥,以及怎么存储和获取
以上3点对于理解解密流程非常重要。
根据官方文档,我梳理了大致的解密流程,如下:

- 小程序客户端调用wx.login,回调里面包含js_code。
- 然后将js_code发送到服务器A(开发者服务器),服务器A向微信服务器发起请求附带js_code、appId、secretkey和grant_type参数,以换取用户的openid和session_key(会话密钥)。
- 服务器A拿到session_key后,生成一个随机数我们叫3rd_session,以3rdSessionId为key,以session_key + openid为value缓存到redis或memcached中;因为微信团队不建议直接将session_key在网络上传输,由开发者自行生成唯一键与session_key关联。其作用是:
- 将3rdSessionId返回给客户端,维护小程序登录态。
- 通过3rdSessionId找到用户session_key和openid。
- 客户端拿到3rdSessionId后缓存到storage,
- 通过wx.getUserIinfo可以获取到用户敏感数据encryptedData 。
- 客户端将encryptedData、3rdSessionId和偏移量一起发送到服务器A
- 服务器A根据3rdSessionId从缓存中获取session_key
- 在服务器A使用AES解密encryptedData,从而实现用户敏感数据解密
重点在6、7、8三个环节。
AES解密三个参数:
- 密文 encryptedData
- 密钥 aesKey
- 偏移向量 iv
服务端解密流程:
- 密文和偏移向量由客户端发送给服务端,对这两个参数在服务端进行Base64_decode解编码操作。
- 根据3rdSessionId从缓存中获取session_key,对session_key进行Base64_decode可以得到aesKey,aes密钥。
- 调用aes解密方法,算法为 AES-128-CBC,数据采用PKCS#7填充。
下面结合小程序实例说明解密流程:
微信登录,获取用户信息
var that = this;
wx.login({
success: function (res) {
//微信js_code
that.setData({wxcode: res.code});
//获取用户信息
wx.getUserInfo({
success: function (res) {
//获取用户敏感数据密文和偏移向量
that.setData({encryptedData: res.encryptedData})
that.setData({iv: res.iv})
}
})
}
})使用code换取3rdSessionId
var httpclient = require('../../utils/httpclient.js')
VAR that = this
//httpclient.req(url, data, method, success, fail)
httpclient.req(
'http://localhost:8090/wxappservice/api/v1/wx/getSession',
{
apiName: 'WX_CODE',
code: this.data.wxcode
},
'GET',
function(result){
var thirdSessionId = result.data.data.sessionId;
that.setData({thirdSessionId: thirdSessionId})
//将thirdSessionId放入小程序缓存
wx.setStorageSync('thirdSessionId', thirdSessionId)
},
function(result){
console.log(result)
}
);发起解密请求
//httpclient.req(url, data, method, success, fail)
httpclient.req(
'http://localhost:8090/wxappservice/api/v1/wx/decodeUserInfo',
{
apiName: 'WX_DECODE_USERINFO',
encryptedData: this.data.encryptedData,
iv: this.data.iv,
sessionId: wx.getStorageSync('thirdSessionId')
},
'GET',
function(result){
//解密后的数据
console.log(result.data)
},
function(result){
console.log(result)
}
);服务端解密实现(java)
/** * 解密用户敏感数据 * @param encryptedData 明文 * @param iv 加密算法的初始向量 * @param sessionId 会话ID * @return */
@Api(name = ApiConstant.WX_DECODE_USERINFO)
@RequestMapping(value = "/api/v1/wx/decodeUserInfo", method = RequestMethod.GET, produces = "application/json")
public Map<String,Object> decodeUserInfo(@RequestParam(required = true,value = "encryptedData")String encryptedData, @RequestParam(required = true,value = "iv")String iv, @RequestParam(required = true,value = "sessionId")String sessionId){ //从缓存中获取session_key
Object wxSessionObj = redisUtil.get(sessionId);
if(null == wxSessionObj){
return rtnParam(40008, null);
}
String wxSessionStr = (String)wxSessionObj;
String sessionKey = wxSessionStr.split("#")[0]; try {
AES aes = new AES();
byte[] resultByte = aes.decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv));
if(null != resultByte && resultByte.length > 0){
String userInfo = new String(resultByte, "UTF-8");
return rtnParam(0, userInfo);
}
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return rtnParam(50021, null);
}AES解密核心代码
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();
}
小程序encryptedData的更多相关文章
- 微信小程序java8 java7 java6 encryptedData 解密 异常处理
使用java8 java7 java6 解密微信小程序encryptedData可以回遇到一些错误 1.java.security.NoSuchAlgorithmException: Cannot ...
- 小程序解密 encryptedData 获取 unionID 等信息
index.php <?php include_once "wxBizDataCrypt.php"; // $appid 由小程序微信官方后台获取 $appid = 'wx4 ...
- 小程序Openid 获取,服务器 encryptedData 解密 遇到的坑
获取客户 openId 和 unionId 需要以下步骤(都为必须步骤) 1.从验证从客户端传上来code, 获取sessionKey (需要配合小程序appid ,secret 发送到微信服务器) ...
- 微信小程序获取用户信息,解密encryptedData 包括敏感数据在内的完整用户信息的加密数据
package com.iups.wx.wxservice; import java.io.UnsupportedEncodingException; import java.security.Alg ...
- .NET 小程序 wx.getUserInfo(OBJECT) 解密 encryptedData 来获取UnionId
在小程序中通过 wx.getUserInfo 获取用户信息,而UnionId 只有关主了公众号才会返回,不关注公众号想获取UnionId则需要我们从返回的 encryptedData 中解码从而获取U ...
- 小程序登录解密用户数据encryptedData -41001: encodingAesKey 非法
问题: 做小程序微信授权登录,先获取code,然后去获取到session_key和open_id,再拿到encryptedData,传到服务器去解密拿到用户信息,但是有时成功,有时返回-41001错误 ...
- 微信小程序加密数据(encryptedData)解密中的PHP代码,php7.1报错
问题描述 最近在开发微信小程序涉及到加密数据(encryptedData)的解密,用的是PHP代码,在运行后报错mcrypt_module_ xxx is deprecated,提示方法已过时了 经研 ...
- 微信小程序之用户数据解密(七)
[未经作者本人同意,请勿以任何形式转载] 经常看到有点的小伙伴在群里问小程序用户数据解密流程,所以打算写一篇关于小程序用户敏感数据解密教程: 加密过程微信服务器完成,解密过程在小程序和自身服务器完成, ...
- 微信小程序-登陆、支付、模板消息
wx.login(OBJECT) 调用接口获取登录凭证(code)进而换取用户登录态信息,包括用户的唯一标识(openid) 及本次登录的 会话密钥(session_key).用户数据的加解密通讯需要 ...
随机推荐
- 第三章 Hyper-V 2012 R2配置选项
原书中的第二章 是介绍了下hyper-v的管理器和检查点的使用,导入导出虚拟机,所以我跳过了不高兴写,很简单.直接进入第三部分,介绍虚拟机的三个重要组成部分:CPU,内存,硬盘的配置选项. Hyper ...
- [SequenceFile_3] MapFile
0. 说明 MapFile 介绍 && 测试 1. 介绍 对 MapFile 的介绍如下: MapFile 是带有索引的 SequenceFile MapFile 是排序的 Seque ...
- OpenLdap 对接内部系统(Gitlab+Wiki+Jumpserver+Openvpn)配置
LDAP 全称轻量级目录访问协议(英文:Lightweight Directory Access Protocol),是一个运行在 TCP/IP 上的目录访问协议.目录是一个特殊的数据库,它的数据经常 ...
- PHP PC端支付宝扫码支付
前面的文章已经描述过在蚂蚁金服开放平台创建应用签约等流程,详见:PHP App端支付宝支付,这里就不多说了,剩下的分两步,第一步是支付前的准备工作,也就是整合支付类文件,我已经整合好可以直接用,代码开 ...
- if语句(初学者)
用if语句可以构成分支结构.它根据给定的条件进行判断,以决定执行某个分支程序段.C语言的if语句有三种基本形式. 1.基本形式:if(表达式)语句 其语义是:如果表达式的值为真,则执行其后的语句,否则 ...
- [Noi2002]Savage(欧几里得拓展)
题意:在一个岛上,有n个野人.这些人开始住在c号洞穴,每一年走p个洞,而且他的生命有L年.问如果岛上的洞穴为一个圈,那么这个圈至少有多少个,才能使他们每年都不在同一个洞穴里. 分析:先假设一种简单的情 ...
- SQL Server中将查询结果转换为Json格式脚本
这篇文章主要介绍了SQL Server中将查询结果转换为Json格式脚本分享,本文直接给出实现代码,需要的朋友可以参考下 原文地址:http://www.jb51.net/article/61462. ...
- 转载 线程池之ThreadPool类与辅助线程 - <第二篇>
http://www.cnblogs.com/kissdodog/archive/2013/03/28/2986026.html 一.CLR线程池 管理线程开销最好的方式: 尽量少的创建线程并且能将线 ...
- OnlineJudgeServer运行
我在这如下这两篇文章都说过青岛OJ相关的 OnlineJudgeFE之前端二次开发 青岛大学开源OJ平台搭建 今天我还是要来讲讲关于这个青岛OJ. 青岛OJ采用的是完全的前后端分离架构. Online ...
- 蒟蒻qxt的sd'日常
emm... 今天刷了一道水题 居然 死循环了 真的是水题啊 顿时自闭 (救救孩子吧) 结果 bug是 我把for循环中的i的值改变了 使得i的值一直都不会达到他的边界值 于是就死循环了 所以 要用到 ...