116 lines
3.5 KiB
C#
116 lines
3.5 KiB
C#
using System.Security.Cryptography;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace CampusErrand.Services;
|
|
|
|
/// <summary>
|
|
/// 微信开放平台服务实现
|
|
/// </summary>
|
|
public class WeChatService : IWeChatService
|
|
{
|
|
private readonly HttpClient _httpClient;
|
|
private readonly string _appId;
|
|
private readonly string _appSecret;
|
|
|
|
public WeChatService(HttpClient httpClient, IConfiguration configuration)
|
|
{
|
|
_httpClient = httpClient;
|
|
var weChatConfig = configuration.GetSection("WeChat");
|
|
_appId = weChatConfig["AppId"]!;
|
|
_appSecret = weChatConfig["AppSecret"]!;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<WeChatSessionResult> Code2SessionAsync(string code)
|
|
{
|
|
var url = $"https://api.weixin.qq.com/sns/jscode2session?appid={_appId}&secret={_appSecret}&js_code={code}&grant_type=authorization_code";
|
|
|
|
var response = await _httpClient.GetAsync(url);
|
|
if (!response.IsSuccessStatusCode)
|
|
{
|
|
return new WeChatSessionResult
|
|
{
|
|
Success = false,
|
|
ErrorMessage = "微信接口调用失败"
|
|
};
|
|
}
|
|
|
|
var json = await response.Content.ReadAsStringAsync();
|
|
Console.WriteLine($"[WeChat] code2session 响应: {json}");
|
|
var result = JsonSerializer.Deserialize<WeChatCode2SessionResponse>(json);
|
|
|
|
if (result == null || result.ErrCode != 0)
|
|
{
|
|
Console.WriteLine($"[WeChat] code2session 失败: errcode={result?.ErrCode}, errmsg={result?.ErrMsg}");
|
|
return new WeChatSessionResult
|
|
{
|
|
Success = false,
|
|
ErrorMessage = result?.ErrMsg ?? "微信接口返回异常"
|
|
};
|
|
}
|
|
|
|
return new WeChatSessionResult
|
|
{
|
|
Success = true,
|
|
SessionKey = result.SessionKey,
|
|
OpenId = result.OpenId
|
|
};
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public string DecryptPhoneNumber(string sessionKey, string encryptedData, string iv)
|
|
{
|
|
var keyBytes = Convert.FromBase64String(sessionKey);
|
|
var ivBytes = Convert.FromBase64String(iv);
|
|
var dataBytes = Convert.FromBase64String(encryptedData);
|
|
|
|
using var aes = Aes.Create();
|
|
aes.Key = keyBytes;
|
|
aes.IV = ivBytes;
|
|
aes.Mode = CipherMode.CBC;
|
|
aes.Padding = PaddingMode.PKCS7;
|
|
|
|
using var decryptor = aes.CreateDecryptor();
|
|
var decryptedBytes = decryptor.TransformFinalBlock(dataBytes, 0, dataBytes.Length);
|
|
var decryptedJson = Encoding.UTF8.GetString(decryptedBytes);
|
|
|
|
var phoneInfo = JsonSerializer.Deserialize<WeChatPhoneInfo>(decryptedJson);
|
|
return phoneInfo?.PhoneNumber ?? throw new InvalidOperationException("解密手机号失败");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 微信 code2Session 响应
|
|
/// </summary>
|
|
internal class WeChatCode2SessionResponse
|
|
{
|
|
[JsonPropertyName("session_key")]
|
|
public string? SessionKey { get; set; }
|
|
|
|
[JsonPropertyName("openid")]
|
|
public string? OpenId { get; set; }
|
|
|
|
[JsonPropertyName("errcode")]
|
|
public int ErrCode { get; set; }
|
|
|
|
[JsonPropertyName("errmsg")]
|
|
public string? ErrMsg { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 微信解密后的手机号信息
|
|
/// </summary>
|
|
internal class WeChatPhoneInfo
|
|
{
|
|
[JsonPropertyName("phoneNumber")]
|
|
public string? PhoneNumber { get; set; }
|
|
|
|
[JsonPropertyName("purePhoneNumber")]
|
|
public string? PurePhoneNumber { get; set; }
|
|
|
|
[JsonPropertyName("countryCode")]
|
|
public string? CountryCode { get; set; }
|
|
}
|