168 lines
5.8 KiB
C#
168 lines
5.8 KiB
C#
using Microsoft.Extensions.Configuration;
|
||
using Microsoft.Extensions.Logging;
|
||
using Newtonsoft.Json;
|
||
using QYZH.InteractiveMagazine.Common.Helpers;
|
||
using QYZH.InteractiveMagazine.IService;
|
||
using QYZH.InteractiveMagazine.IService.Dto;
|
||
using QYZH.InteractiveMagazine.Models.Common;
|
||
using QYZH.InteractiveMagazine.Models.Settings;
|
||
using QYZH.InteractiveMagazine.Infrastructure.Auth;
|
||
|
||
namespace QYZH.InteractiveMagazine.Service;
|
||
|
||
/// <summary>
|
||
/// 微信小程序服务实现
|
||
/// </summary>
|
||
public class WeChatMiniProgramService : IWeChatMiniProgramService
|
||
{
|
||
private readonly IConfiguration _configuration;
|
||
private readonly ILogger<WeChatMiniProgramService> _logger;
|
||
private const string Code2SessionUrl = "https://api.weixin.qq.com/sns/jscode2session";
|
||
private const string GetPhoneNumberUrl = "https://api.weixin.qq.com/wxa/business/getuserphonenumber";
|
||
|
||
/// <summary>
|
||
/// 构造函数
|
||
/// </summary>
|
||
/// <param name="configuration">配置</param>
|
||
/// <param name="logger">日志记录器</param>
|
||
public WeChatMiniProgramService(IConfiguration configuration, ILogger<WeChatMiniProgramService> logger)
|
||
{
|
||
_configuration = configuration;
|
||
_logger = logger;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 微信登录
|
||
/// </summary>
|
||
/// <param name="code">微信登录凭证</param>
|
||
/// <returns>微信登录结果</returns>
|
||
public async Task<WeChatLoginOutput> WeChatLoginAsync(string code)
|
||
{
|
||
_logger.LogInformation("微信登录尝试,code: {Code}", code);
|
||
|
||
if (string.IsNullOrWhiteSpace(code))
|
||
{
|
||
throw new BusinessException("登录凭证不能为空", 400);
|
||
}
|
||
|
||
// 获取微信配置
|
||
var weChatSettings = GetWeChatSettings();
|
||
|
||
if (string.IsNullOrWhiteSpace(weChatSettings.AppId) || string.IsNullOrWhiteSpace(weChatSettings.AppSecret))
|
||
{
|
||
throw new BusinessException("微信配置不完整", 500);
|
||
}
|
||
|
||
// 演示版本:模拟调用微信code2session接口
|
||
var openId = await SimulateCode2SessionAsync(code, weChatSettings);
|
||
|
||
// 获取JWT配置并生成令牌
|
||
var jwtSettings = GetJwtSettings();
|
||
var token = JwtHelper.GenerateToken(1, "微信用户", jwtSettings);
|
||
|
||
_logger.LogInformation("微信登录成功,openId: {OpenId}", openId);
|
||
|
||
return new WeChatLoginOutput
|
||
{
|
||
Token = token,
|
||
UserId = 1,
|
||
UserName = "微信用户",
|
||
OpenId = openId
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取手机号
|
||
/// </summary>
|
||
/// <param name="code">获取手机号凭证</param>
|
||
/// <returns>手机号信息</returns>
|
||
public async Task<WeChatPhoneNumberOutput> GetPhoneNumberAsync(string code)
|
||
{
|
||
_logger.LogInformation("获取微信手机号尝试,code: {Code}", code);
|
||
|
||
if (string.IsNullOrWhiteSpace(code))
|
||
{
|
||
throw new BusinessException("获取手机号凭证不能为空", 400);
|
||
}
|
||
|
||
// 演示版本:模拟返回手机号
|
||
var phoneNumber = await SimulateGetPhoneNumberAsync(code);
|
||
|
||
_logger.LogInformation("获取微信手机号成功");
|
||
|
||
return new WeChatPhoneNumberOutput
|
||
{
|
||
PhoneNumber = phoneNumber
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 模拟调用微信code2session接口
|
||
/// </summary>
|
||
/// <param name="code">登录凭证</param>
|
||
/// <param name="weChatSettings">微信配置</param>
|
||
/// <returns>openId</returns>
|
||
private async Task<string> SimulateCode2SessionAsync(string code, WeChatSettings weChatSettings)
|
||
{
|
||
// 演示版本:模拟返回openId
|
||
// 实际实现应调用微信API:
|
||
// var url = $"{Code2SessionUrl}?appid={weChatSettings.AppId}&secret={weChatSettings.AppSecret}&js_code={code}&grant_type=authorization_code";
|
||
// var response = await HttpHelper.GetAsync<dynamic>(url);
|
||
// if (response?.errcode == 0) return response.openid;
|
||
|
||
await Task.Delay(100); // 模拟网络请求延迟
|
||
|
||
return $"demo_openid_{code.GetHashCode():X}";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 模拟调用微信获取手机号接口
|
||
/// </summary>
|
||
/// <param name="code">获取手机号凭证</param>
|
||
/// <returns>手机号</returns>
|
||
private async Task<string> SimulateGetPhoneNumberAsync(string code)
|
||
{
|
||
// 演示版本:模拟返回手机号
|
||
// 实际实现应调用微信API获取access_token,然后调用获取手机号接口:
|
||
// var tokenUrl = $"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={appId}&secret={appSecret}";
|
||
// var tokenResponse = await HttpHelper.GetAsync<dynamic>(tokenUrl);
|
||
// var accessToken = tokenResponse.access_token;
|
||
// var phoneUrl = $"{GetPhoneNumberUrl}?access_token={accessToken}";
|
||
// var phoneResponse = await HttpHelper.PostAsync<dynamic>(phoneUrl, new { code });
|
||
|
||
await Task.Delay(100); // 模拟网络请求延迟
|
||
|
||
return "13800138000";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取微信配置
|
||
/// </summary>
|
||
/// <returns>微信配置对象</returns>
|
||
private WeChatSettings GetWeChatSettings()
|
||
{
|
||
return _configuration.GetSection("WeChatSettings").Get<WeChatSettings>()
|
||
?? new WeChatSettings
|
||
{
|
||
AppId = "demo_app_id",
|
||
AppSecret = "demo_app_secret"
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取JWT配置
|
||
/// </summary>
|
||
/// <returns>JWT配置对象</returns>
|
||
private JwtSettings GetJwtSettings()
|
||
{
|
||
return _configuration.GetSection("JwtSettings").Get<JwtSettings>()
|
||
?? new JwtSettings
|
||
{
|
||
Issuer = "QYZH.InteractiveMagazine",
|
||
Audience = "QYZH.InteractiveMagazine.Client",
|
||
SecretKey = "QYZH_InteractiveMagazine_SecretKey_2024",
|
||
ExpiryMinutes = 120
|
||
};
|
||
}
|
||
}
|