.NET Core 获取小程序手机号并解析

发布时间 2023-06-27 14:09:36作者: study_record

方法一:

1. 小程序提供 微信用户授权后的 code,用户手机号的加密数据和iv。
2. 使用 code 换取 sessionkey。
3.  解密用户手机号的加密数据。

参考代码

        /// <summary>
        /// 获取openid,sessionkey
        /// </summary>
        /// <param name="appID"></param>
        /// <param name="appSecret"></param>
        /// <param name="code"></param>
        /// <returns>返回opendid,sessionkey</returns>
        public async Task<(string, string)> GetOpenIdAsync(string appID, string appSecret, string code)
        {
            //用于小程序登录
            var url = $"{WeChat_url}?appid={appID}&secret={appSecret}&js_code={code}&grant_type=authorization_code";

            var handler = new HttpClientHandler();
            handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

            using (var client = new HttpClient(handler))
            {
                var response = await client.GetAsync(url);
                if (response.IsSuccessStatusCode)
                {
                    var content = await response.Content.ReadAsStringAsync();
                    var result = JsonConvert.DeserializeObject<JObject>(content);

                    _log4.LogInfo($"GetOpenIdAsync返回:{result}");

                    if (result.ContainsKey("openid"))
                    {
                        var openId = result["openid"].ToString();
                        var sessionkey = result["session_key"].ToString();
                        return (openId, sessionkey);
                    }
                    else
                    {
                        _log4.LogError($"GetOpenIdAsync失败:{result}");
                    }
                }
            }
            return ("", "");
        }
        /// <summary>
        /// 解析手机号
        /// </summary>
        /// <param name="encryptedData"></param>
        /// <param name="sessionKey"></param>
        /// <param name="iv"></param>
        /// <returns></returns>
        private string DecryptPhoneNumber(string encryptedData, string sessionKey, string iv)
        {
            var encryptedDataBytes = Convert.FromBase64String(encryptedData);
            var sessionKeyBytes = Convert.FromBase64String(sessionKey);
            var ivBytes = Convert.FromBase64String(iv);

            using (var aes = Aes.Create())
            {
                aes.Key = sessionKeyBytes;
                aes.IV = ivBytes;
                aes.Mode = CipherMode.CBC;
                aes.Padding = PaddingMode.PKCS7;

                using (var decryptor = aes.CreateDecryptor())
                {
                    var decryptedData = decryptor.TransformFinalBlock(encryptedDataBytes, 0, encryptedDataBytes.Length);
                    var decryptedString = Encoding.UTF8.GetString(decryptedData);

                    var result = JsonConvert.DeserializeObject<JObject>(decryptedString);
                    var phoneNumber = result["phoneNumber"].ToString();
                    //var phoneNumber = JObject.Parse(decryptedString)["phoneNumber"].Value<string>();
                    return phoneNumber;
                }
            }
        }

方法二:
1. 获取微信用户授权后的 code。

2. 使用 code 换取 access_token 和 openid。

3. 使用 access_token 和 openid 获取用户手机号的加密数据。

4. 解密用户手机号的加密数据。

using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json.Linq;

public class WeChatService
{
    private readonly IConfiguration _configuration;
    private readonly HttpClient _httpClient;

    public WeChatService(IConfiguration configuration, HttpClient httpClient)
    {
        _configuration = configuration;
        _httpClient = httpClient;
    }

    public async Task<string> GetPhoneNumberAsync(string code, string encryptedData, string iv)
    {
        var appId = _configuration["WeChat:AppId"];
        var appSecret = _configuration["WeChat:AppSecret"];

        // 获取 access_token 和 openid
        var accessTokenUrl = $"https://api.weixin.qq.com/sns/oauth2/access_token?appid={appId}&secret={appSecret}&code={code}&grant_type=authorization_code";
        var accessTokenResponse = await _httpClient.GetAsync(accessTokenUrl);
        var accessTokenJson = await accessTokenResponse.Content.ReadAsStringAsync();
        var accessToken = JObject.Parse(accessTokenJson)["access_token"].Value<string>();
        var openid = JObject.Parse(accessTokenJson)["openid"].Value<string>();

        // 获取用户手机号的加密数据
        var phoneNumberUrl = $"https://api.weixin.qq.com/sns/userinfo?access_token={accessToken}&openid={openid}&lang=zh_CN";
        var phoneNumberResponse = await _httpClient.GetAsync(phoneNumberUrl);
        var phoneNumberJson = await phoneNumberResponse.Content.ReadAsStringAsync();
        var phoneNumberEncryptedData = JObject.Parse(phoneNumberJson)["encrypted_data"].Value<string>();

        // 解密用户手机号的加密数据
        var sessionKey = JObject.Parse(accessTokenJson)["session_key"].Value<string>();
        var phoneNumber = DecryptPhoneNumber(phoneNumberEncryptedData, sessionKey, iv);

        return phoneNumber;
    }

    private string DecryptPhoneNumber(string encryptedData, string sessionKey, string iv)
    {
        var encryptedDataBytes = Convert.FromBase64String(encryptedData);
        var sessionKeyBytes = Convert.FromBase64String(sessionKey);
        var ivBytes = Convert.FromBase64String(iv);

        using (var aes = Aes.Create())
        {
            aes.Key = sessionKeyBytes;
            aes.IV = ivBytes;
            aes.Mode = CipherMode.CBC;
            aes.Padding = PaddingMode.PKCS7;

            using (var decryptor = aes.CreateDecryptor())
            {
                var decryptedData = decryptor.TransformFinalBlock(encryptedDataBytes, 0, encryptedDataBytes.Length);
                var decryptedString = Encoding.UTF8.GetString(decryptedData);

                var phoneNumber = JObject.Parse(decryptedString)["phoneNumber"].Value<string>();
                return phoneNumber;
            }
        }
    }
}