2025-06-06 14:57:20 +08:00

143 lines
5.3 KiB
C#

using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using YD_WeChatApplet.WeChat.Lib;
namespace YD_WeChatApplet.WeChat
{
/// <summary>
/// 微信小程序登录接口
/// </summary>
public class WeChatAppDecrypt
{
// 构造函数
// public WeChatAppDecrypt(IConfiguration configuration)
// {
// Configuration = configuration;
// }
/// <summary>
/// 获取OpenId和SessionKey的Json数据包
/// </summary>
/// <param name="code">客户端发来的code</param>
/// <returns>Json数据包</returns>
private string GetOpenIdAndSessionKeyString(string code, string appid, string secret)
{
string temp = "https://api.weixin.qq.com/sns/jscode2session?" +
"appid=" + appid
+ "&secret=" + secret
+ "&js_code=" + code
+ "&grant_type=authorization_code";
return HttpService.Get(temp);
}
/// <summary>
/// 反序列化包含OpenId和SessionKey的Json数据包
/// </summary>
/// <param name="loginInfo">Json数据包</param>
/// <returns>包含OpenId和SessionKey的类</returns>
public OpenIdAndSessionKey DecodeOpenIdAndSessionKey(WechatLoginInfo loginInfo)
{
var res = GetOpenIdAndSessionKeyString(loginInfo.code, loginInfo.appid, loginInfo.secret);
OpenIdAndSessionKey oiask = JsonConvert.DeserializeObject<OpenIdAndSessionKey>(res);
if (!String.IsNullOrEmpty(oiask.errcode))
return null;
return oiask;
}
/// <summary>
/// 根据微信小程序平台提供的解密算法解密数据,推荐直接使用此方法
/// </summary>
/// <param name="loginInfo">登陆信息</param>
/// <returns>用户信息</returns>
public WechatUserInfo Decrypt(WechatLoginInfo loginInfo)
{
if (loginInfo == null || string.IsNullOrEmpty(loginInfo.code))
return null;
OpenIdAndSessionKey oiask = DecodeOpenIdAndSessionKey(loginInfo);
if (oiask == null)
return null;
WechatUserInfo userInfo;
//if (!String.IsNullOrWhiteSpace(oiask.openid) && !string.IsNullOrWhiteSpace(loginInfo.rawData))
//{
// userInfo = JsonConvert.DeserializeObject<WechatUserInfo>(loginInfo.rawData);
// userInfo.openId = oiask.openid;
// //userInfo.unionId = oiask.unionId;
// return userInfo;
//}
// 解密过程
userInfo = Decrypt(loginInfo.encryptedData, loginInfo.iv, oiask.session_key);
userInfo.openId = oiask.openid;
return userInfo;
}
/// <summary>
/// 根据微信小程序平台提供的解密算法解密数据
/// </summary>
/// <param name="encryptedData">加密数据</param>
/// <param name="iv">初始向量</param>
/// <param name="sessionKey">从服务端获取的SessionKey</param>
/// <returns>解密后的用户信息</returns>
public WechatUserInfo Decrypt(string encryptedData, string iv, string sessionKey)
{
// 创建解密器生成工具实例
AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
aes.Mode = CipherMode.CBC;
aes.BlockSize = 128;
aes.Padding = PaddingMode.PKCS7;
// 格式化待处理字符串
byte[] byte_encryptedData = Convert.FromBase64String(encryptedData);
byte[] byte_iv = Convert.FromBase64String(iv);
byte[] byte_sessionKey = Convert.FromBase64String(sessionKey);
aes.IV = byte_iv;
aes.Key = byte_sessionKey;
// 创建解密器
ICryptoTransform transform = aes.CreateDecryptor(aes.Key, aes.IV);
byte[] decryptedData;
// 使用 CryptoStream 解密数据
using (var ms = new MemoryStream())
using (var cs = new CryptoStream(ms, transform, CryptoStreamMode.Write))
{
cs.Write(byte_encryptedData, 0, byte_encryptedData.Length);
cs.FlushFinalBlock();
decryptedData = ms.ToArray();
}
// 去除解密后的数据的填充部分
string result = Encoding.UTF8.GetString(RemovePadding(decryptedData));
// 反序列化并返回用户信息
WechatUserInfo userInfo = JsonConvert.DeserializeObject<WechatUserInfo>(result);
return userInfo;
}
/// <summary>
/// 移除填充字节
/// </summary>
/// <param name="decrypted">解密后的数据</param>
/// <returns>去除填充后的数据</returns>
private static byte[] RemovePadding(byte[] decrypted)
{
int pad = decrypted[decrypted.Length - 1];
if (pad < 1 || pad > 32)
{
pad = 0;
}
byte[] result = new byte[decrypted.Length - pad];
Array.Copy(decrypted, result, result.Length);
return result;
}
}
}