150 lines
No EOL
5.6 KiB
C#
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);
|
|
}
|
|
}
|
|
} |