using System; using System.Security.Cryptography; using System.Text; using BCrypt.Net; using CncModels.Constants; using CncModels.Dto.Login; using CncService.Interface; using CncService; using CncRepository.Interface; using System.Linq; namespace CncService.Impl { /// /// 登录认证实现 /// public class AuthService : IAuthService { private readonly ISysConfigRepository _sysConfigRepository; private readonly string _jwtSecret; public AuthService(ISysConfigRepository sysConfigRepository, string jwtSecret) { _sysConfigRepository = sysConfigRepository ?? throw new ArgumentNullException(nameof(sysConfigRepository)); _jwtSecret = jwtSecret ?? throw new ArgumentNullException(nameof(jwtSecret)); } /// public LoginResponse Login(LoginRequest request) { if (request == null) throw new BusinessException(ErrorCode.BadRequest, "请求参数错误"); // 读取管理员用户名与哈希 var userCfg = _sysConfigRepository.GetByKey("admin_username"); var pwdCfg = _sysConfigRepository.GetByKey("admin_password_hash"); var usernameStored = userCfg?.ConfigValue; var passwordHash = pwdCfg?.ConfigValue; if (string.IsNullOrWhiteSpace(usernameStored) || string.IsNullOrWhiteSpace(passwordHash)) { throw new BusinessException(ErrorCode.BadRequest, "用户名或密码错误"); } if (!string.Equals(request.Username, usernameStored, StringComparison.OrdinalIgnoreCase)) { throw new BusinessException(ErrorCode.BadRequest, "用户名或密码错误"); } // 验证密码 if (!BCrypt.Net.BCrypt.Verify(request.Password ?? string.Empty, passwordHash)) { throw new BusinessException(ErrorCode.BadRequest, "用户名或密码错误"); } // 过期时间 int expiresIn = (request.RememberMe ?? false) ? 24 * 3600 : 8 * 3600; // 生成简易 JWT var token = GenerateJwtToken(request.Username, expiresIn); return new LoginResponse { Token = token, ExpiresIn = expiresIn }; } private string GenerateJwtToken(string username, int expiresInSeconds) { // Header const string headerJson = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}"; long exp = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + expiresInSeconds; // Payload string payloadJson = $"{{\"sub\":\"admin\",\"name\":\"{Escape(username)}\",\"exp\":{exp}}}"; string header = Base64UrlEncode(Encoding.UTF8.GetBytes(headerJson)); string payload = Base64UrlEncode(Encoding.UTF8.GetBytes(payloadJson)); string unsigned = header + "." + payload; // Signature using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(_jwtSecret))) { var sig = hmac.ComputeHash(Encoding.UTF8.GetBytes(unsigned)); string signature = Base64UrlEncode(sig); return unsigned + "." + signature; } } private string Escape(string input) { if (string.IsNullOrEmpty(input)) return string.Empty; return input.Replace("\\", "\\\\").Replace("\"", "\\\""); } private string Base64UrlEncode(byte[] input) { var base64 = Convert.ToBase64String(input); return base64.Replace("+", "-").Replace("/", "_").TrimEnd('='); } } }