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('=');
}
}
}