You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
3.7 KiB
C#
102 lines
3.7 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// 登录认证实现
|
|
/// </summary>
|
|
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));
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
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('=');
|
|
}
|
|
}
|
|
}
|