162 lines
4.8 KiB
C#
162 lines
4.8 KiB
C#
using AmtScanner.Api.Data;
|
|
using AmtScanner.Api.Models;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace AmtScanner.Api.Services;
|
|
|
|
/// <summary>
|
|
/// 认证服务实现
|
|
/// </summary>
|
|
public class AuthService : IAuthService
|
|
{
|
|
private readonly AppDbContext _context;
|
|
private readonly IJwtService _jwtService;
|
|
|
|
public AuthService(AppDbContext context, IJwtService jwtService)
|
|
{
|
|
_context = context;
|
|
_jwtService = jwtService;
|
|
}
|
|
|
|
public async Task<(User? user, string? accessToken, string? refreshToken, string? error)> LoginAsync(string userName, string password)
|
|
{
|
|
// 查找用户
|
|
var user = await _context.Users
|
|
.FirstOrDefaultAsync(u => u.UserName == userName && !u.IsDeleted);
|
|
|
|
if (user == null)
|
|
{
|
|
return (null, null, null, "用户名或密码错误");
|
|
}
|
|
|
|
// 验证密码
|
|
if (!BCrypt.Net.BCrypt.Verify(password, user.PasswordHash))
|
|
{
|
|
return (null, null, null, "用户名或密码错误");
|
|
}
|
|
|
|
// 检查用户状态
|
|
if (user.Status != "1")
|
|
{
|
|
return (null, null, null, "用户已被禁用");
|
|
}
|
|
|
|
// 获取用户角色
|
|
var roles = await GetUserRolesAsync(user.Id);
|
|
|
|
// 生成 Token
|
|
var accessToken = _jwtService.GenerateAccessToken(user, roles);
|
|
var refreshToken = _jwtService.GenerateRefreshToken();
|
|
|
|
// 保存 RefreshToken 到用户
|
|
user.RefreshToken = refreshToken;
|
|
user.RefreshTokenExpiryTime = _jwtService.GetRefreshTokenExpiryTime();
|
|
await _context.SaveChangesAsync();
|
|
|
|
return (user, accessToken, refreshToken, null);
|
|
}
|
|
|
|
public async Task<(string? accessToken, string? refreshToken, string? error)> RefreshTokenAsync(string accessToken, string refreshToken)
|
|
{
|
|
// 从过期的 Token 中获取用户信息
|
|
var principal = _jwtService.GetPrincipalFromExpiredToken(accessToken);
|
|
if (principal == null)
|
|
{
|
|
return (null, null, "无效的 Token");
|
|
}
|
|
|
|
var userIdClaim = principal.FindFirst("userId")?.Value;
|
|
if (string.IsNullOrEmpty(userIdClaim) || !int.TryParse(userIdClaim, out var userId))
|
|
{
|
|
return (null, null, "无效的 Token");
|
|
}
|
|
|
|
// 查找用户
|
|
var user = await _context.Users
|
|
.FirstOrDefaultAsync(u => u.Id == userId && !u.IsDeleted);
|
|
|
|
if (user == null)
|
|
{
|
|
return (null, null, "用户不存在");
|
|
}
|
|
|
|
// 验证 RefreshToken
|
|
if (user.RefreshToken != refreshToken || user.RefreshTokenExpiryTime <= DateTime.UtcNow)
|
|
{
|
|
return (null, null, "RefreshToken 无效或已过期");
|
|
}
|
|
|
|
// 获取用户角色
|
|
var roles = await GetUserRolesAsync(user.Id);
|
|
|
|
// 生成新的 Token
|
|
var newAccessToken = _jwtService.GenerateAccessToken(user, roles);
|
|
var newRefreshToken = _jwtService.GenerateRefreshToken();
|
|
|
|
// 更新 RefreshToken
|
|
user.RefreshToken = newRefreshToken;
|
|
user.RefreshTokenExpiryTime = _jwtService.GetRefreshTokenExpiryTime();
|
|
await _context.SaveChangesAsync();
|
|
|
|
return (newAccessToken, newRefreshToken, null);
|
|
}
|
|
|
|
public async Task<bool> LogoutAsync(int userId)
|
|
{
|
|
var user = await _context.Users.FindAsync(userId);
|
|
if (user == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 清除 RefreshToken
|
|
user.RefreshToken = null;
|
|
user.RefreshTokenExpiryTime = null;
|
|
await _context.SaveChangesAsync();
|
|
|
|
return true;
|
|
}
|
|
|
|
public async Task<User?> GetUserByIdAsync(int userId)
|
|
{
|
|
return await _context.Users
|
|
.FirstOrDefaultAsync(u => u.Id == userId && !u.IsDeleted);
|
|
}
|
|
|
|
public async Task<List<string>> GetUserRolesAsync(int userId)
|
|
{
|
|
return await _context.UserRoles
|
|
.Where(ur => ur.UserId == userId)
|
|
.Join(_context.Roles, ur => ur.RoleId, r => r.Id, (ur, r) => r)
|
|
.Where(r => r.Enabled)
|
|
.Select(r => r.RoleCode)
|
|
.ToListAsync();
|
|
}
|
|
|
|
public async Task<(List<User> users, int total)> GetUsersAsync(int current, int size, string? userName = null, string? status = null)
|
|
{
|
|
var query = _context.Users.Where(u => !u.IsDeleted);
|
|
|
|
// 按用户名筛选
|
|
if (!string.IsNullOrEmpty(userName))
|
|
{
|
|
query = query.Where(u => u.UserName.Contains(userName));
|
|
}
|
|
|
|
// 按状态筛选
|
|
if (!string.IsNullOrEmpty(status))
|
|
{
|
|
query = query.Where(u => u.Status == status);
|
|
}
|
|
|
|
var total = await query.CountAsync();
|
|
var users = await query
|
|
.OrderByDescending(u => u.CreatedAt)
|
|
.Skip((current - 1) * size)
|
|
.Take(size)
|
|
.ToListAsync();
|
|
|
|
return (users, total);
|
|
}
|
|
}
|