iFileProxy/src/Services/AuthService.cs
2024-12-02 23:41:24 +08:00

150 lines
No EOL
5.6 KiB
C#

using BCrypt.Net;
using iFileProxy.Models;
using System.Security.Claims;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using System.Text;
namespace iFileProxy.Services
{
public class AuthService
{
private readonly DatabaseGateService _dbGateService;
private readonly IConfiguration _configuration;
private readonly ILogger<AuthService> _logger;
public AuthService(DatabaseGateService dbGateService, IConfiguration configuration, ILogger<AuthService> logger)
{
_dbGateService = dbGateService;
_configuration = configuration;
_logger = logger;
}
public async Task<(bool success, string message)> RegisterAsync(RegisterRequest request, string ipAddr)
{
try
{
// 检查用户名是否已存在
if (await _dbGateService.UserExistsAsync(request.Username, request.Email))
{
return (false, "用户名或电子邮件已存在");
}
// 检查是否是第一个用户
var isFirstUser = await _dbGateService.GetUserCountAsync() == 0;
// 创建新用户
var user = new User
{
Username = request.Username,
PasswordHash = BCrypt.Net.BCrypt.HashPassword(request.Password),
LastLoginIP = ipAddr,
// 如果是第一个用户,设置为超级管理员
Mask = isFirstUser ? UserMask.SuperAdmin : UserMask.User,
Nickname = request.NickName,
Email = request.Email,
};
// 保存用户
await _dbGateService.CreateUserAsync(user);
// 记录注册事件
var userEvent = new UserEvent
{
UserId = user.UserId,
EventType = UserEventType.Registry,
EventIP = ipAddr,
EventDetail = isFirstUser ? "超级管理员注册" : "用户注册"
};
await _dbGateService.CreateUserEventAsync(userEvent);
return (true, isFirstUser ? "超级管理员注册成功" : "注册成功");
}
catch (Exception ex)
{
_logger.LogError(ex, "用户注册失败");
return (false, "注册失败");
}
}
public async Task<(bool success, string token, string message)> LoginAsync(string account, string password, string ip, string userAgent, string fingerprint)
{
try
{
var user = await _dbGateService.GetUserByAccountAsync(account);
if (user == null)
{
return (false, string.Empty, "用户不存在");
}
if (user.State == UserState.Blocked)
{
return (false, string.Empty, "账户已被封禁");
}
if (!BCrypt.Net.BCrypt.Verify(password, user.PasswordHash))
{
return (false, string.Empty, "密码错误");
}
// 更新登录信息
user.LastLoginTime = DateTime.Now;
user.LastLoginIP = ip;
await _dbGateService.UpdateUserAsync(user);
// 记录登录事件
var userEvent = new UserEvent
{
UserId = user.UserId,
EventType = UserEventType.Login,
EventIP = ip,
EventDetail = $"用户通过{(account.Contains('@') ? "" : "")}登录"
};
await _dbGateService.CreateUserEventAsync(userEvent);
// 生成包含客户端信息的token
var token = GenerateJwtToken(user, new ClientInfo
{
IP = ip,
UserAgent = userAgent,
Fingerprint = fingerprint
});
return (true, token, "登录成功");
}
catch (Exception ex)
{
_logger.LogError(ex, "用户登录失败");
return (false, string.Empty, "登录失败");
}
}
private string GenerateJwtToken(User user, ClientInfo clientInfo)
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, user.UserId),
new Claim(ClaimTypes.Name, user.Username),
new Claim(ClaimTypes.Role, user.Mask.ToString()),
new Claim("ip", clientInfo.IP),
new Claim("userAgent", clientInfo.UserAgent),
new Claim("fingerprint", clientInfo.Fingerprint)
};
// 确保密钥至少32字节长
var key = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_configuration["Jwt:Key"] ??
"iFileProxy-JWT-Secret-Key-2024-Very-Long-Secret-Key-For-Security"));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _configuration["Jwt:Issuer"] ?? "iFileProxy",
audience: _configuration["Jwt:Audience"] ?? "iFileProxy.Client",
claims: claims,
expires: DateTime.Now.AddDays(1),
signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(token);
}
}
}