using CsharpHttpHelper; using System; using System.Threading.Tasks; using System.ComponentModel.DataAnnotations; namespace Work.Store.Api; public sealed class LoginRequest { [Required] public string UserName { get; set; } /// UTF-8 密码的 32 位大写 MD5,由调用方计算。 [Required] public string Password { get; set; } [StringLength(100)] public string DeviceId { get; set; } [StringLength(100)] public string DeviceName { get; set; } } public sealed class LoginResult { public string TokenType { get; set; } = "Bearer"; public string Token { get; set; } public uint ExpiresInMinutes { get; set; } } public sealed class AuthApi { private readonly ApiTransport _transport; private readonly string _deviceId; public AuthApi(string baseUrl) : this(new ApiTransport(baseUrl)) { } public AuthApi(ApiTransport transport, string deviceId = null) { _transport = transport ?? throw new ArgumentNullException(nameof(transport)); _deviceId = deviceId; } /// 同步登录,凭据快照仅存内存,供 401 时自动重登;界面调用需放在后台线程。 public LoginResult Login(LoginRequest request) { if (request == null) throw new ArgumentNullException(nameof(request)); var credentials = new LoginRequest { UserName = request.UserName, Password = request.Password, DeviceId = _deviceId ?? request.DeviceId, DeviceName = request.DeviceName }; _transport.SessionGate.Wait(); try { var result = LoginCore(_transport, credentials); _transport.SetSession(result.Token, credentials); return result; } finally { _transport.SessionGate.Release(); } } internal static LoginResult LoginCore(ApiTransport transport, LoginRequest request) { var result = transport.GetRequired("Auth/Login", MethodType.Post, request, authenticated: false); return ValidateToken(result); } internal static async Task LoginCoreAsync(ApiTransport transport, LoginRequest request) { var result = await transport.GetRequiredAsync("Auth/Login", MethodType.Post, request, authenticated: false).ConfigureAwait(false); return ValidateToken(result); } private static LoginResult ValidateToken(LoginResult result) { if (result == null || string.IsNullOrWhiteSpace(result.Token) || result.Token.IndexOfAny(new[] { '\r', '\n' }) >= 0 || !string.Equals(result.TokenType, "Bearer", StringComparison.OrdinalIgnoreCase)) throw new HttpException("登录响应缺少有效的 Bearer Token。"); return result; } }