using Microsoft.Extensions.Options; using System.Net.Http.Json; using System.Text.Json.Serialization; using TakeoutSaaS.Application.Identity.Abstractions; using TakeoutSaaS.Infrastructure.Identity.Options; using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; namespace TakeoutSaaS.Infrastructure.Identity.Services; /// /// 微信 code2Session 实现 /// public sealed class WeChatAuthService(HttpClient httpClient, IOptions options) : IWeChatAuthService { private readonly WeChatMiniOptions _options = options.Value; /// /// 调用微信接口完成 code2Session。 /// /// 临时登录凭证 code。 /// 取消标记。 /// 微信会话信息。 public async Task Code2SessionAsync(string code, CancellationToken cancellationToken = default) { // 1. 拼装请求地址 var requestUri = $"sns/jscode2session?appid={Uri.EscapeDataString(_options.AppId)}&secret={Uri.EscapeDataString(_options.Secret)}&js_code={Uri.EscapeDataString(code)}&grant_type=authorization_code"; using var response = await httpClient.GetAsync(requestUri, cancellationToken); response.EnsureSuccessStatusCode(); // 2. 读取响应 var payload = await response.Content.ReadFromJsonAsync(cancellationToken: cancellationToken); if (payload == null) { throw new BusinessException(ErrorCodes.Unauthorized, "微信登录失败:响应为空"); } // 3. 校验错误码 if (payload.ErrorCode.HasValue && payload.ErrorCode.Value != 0) { var message = string.IsNullOrWhiteSpace(payload.ErrorMessage) ? $"微信登录失败,错误码:{payload.ErrorCode}" : payload.ErrorMessage; throw new BusinessException(ErrorCodes.Unauthorized, message); } // 4. 校验必要字段 if (string.IsNullOrWhiteSpace(payload.OpenId) || string.IsNullOrWhiteSpace(payload.SessionKey)) { throw new BusinessException(ErrorCodes.Unauthorized, "微信登录失败:返回数据无效"); } // 5. 组装会话信息 return new WeChatSessionInfo { OpenId = payload.OpenId, UnionId = payload.UnionId, SessionKey = payload.SessionKey }; } private sealed class WeChatSessionResponse { [JsonPropertyName("openid")] public string? OpenId { get; set; } [JsonPropertyName("unionid")] public string? UnionId { get; set; } [JsonPropertyName("session_key")] public string? SessionKey { get; set; } [JsonPropertyName("errcode")] public int? ErrorCode { get; set; } [JsonPropertyName("errmsg")] public string? ErrorMessage { get; set; } } }