LingAdmin/Backend/LingAdmin.API/Controllers/AuthController.cs

218 lines
7.2 KiB
C#
Raw Permalink Normal View History

2026-04-16 18:13:06 +08:00
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using LingAdmin.API.Data;
using LingAdmin.API.Models;
using LingAdmin.API.DTOs;
using LingAdmin.API.Services;
using Dapr.Client;
namespace LingAdmin.API.Controllers;
[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
private readonly AppDbContext _context;
private readonly IPasswordHasher _passwordHasher;
private readonly ITokenService _tokenService;
private readonly DaprClient _daprClient;
private readonly ILogger<AuthController> _logger;
public AuthController(
AppDbContext context,
IPasswordHasher passwordHasher,
ITokenService tokenService,
DaprClient daprClient,
ILogger<AuthController> logger)
{
_context = context;
_passwordHasher = passwordHasher;
_tokenService = tokenService;
_daprClient = daprClient;
_logger = logger;
}
[HttpPost("register")]
public async Task<ActionResult<ApiResponse<UserDto>>> Register(RegisterDto registerDto)
{
try
{
// Validate input
if (string.IsNullOrWhiteSpace(registerDto.Email) ||
string.IsNullOrWhiteSpace(registerDto.Password))
{
return BadRequest(ApiResponse<UserDto>.Error("Email and password are required", 400));
}
// Check if user already exists
if (await _context.Users.AnyAsync(u => u.Email == registerDto.Email))
{
return BadRequest(ApiResponse<UserDto>.Error("User with this email already exists", 400));
}
// Create new user
var user = new User
{
Name = registerDto.Name,
Email = registerDto.Email,
Role = registerDto.Role,
Status = "Active",
PasswordHash = _passwordHasher.HashPassword(registerDto.Password),
CreatedAt = DateTime.UtcNow
};
_context.Users.Add(user);
await _context.SaveChangesAsync();
// Publish user created event
await _daprClient.PublishEventAsync("pubsub", "user-created", new
{
userId = user.Id,
email = user.Email,
name = user.Name,
timestamp = DateTime.UtcNow
});
_logger.LogInformation("User registered successfully: {Email}", user.Email);
var userDto = MapToUserDto(user);
return CreatedAtAction(nameof(GetProfile), new { id = user.Id }, ApiResponse<UserDto>.Success(userDto));
}
catch (Exception ex)
{
_logger.LogError(ex, "Error during user registration");
return StatusCode(500, ApiResponse<UserDto>.Error("Internal server error", 500));
}
}
[HttpPost("login")]
public async Task<ActionResult<ApiResponse<LoginResponseDto>>> Login(LoginDto loginDto)
{
try
{
// Find user by email
var user = await _context.Users.FirstOrDefaultAsync(u => u.Email == loginDto.Email);
if (user == null)
{
return Unauthorized(ApiResponse<LoginResponseDto>.Error("Invalid email or password", 401));
}
// Verify password
if (!_passwordHasher.VerifyPassword(loginDto.Password, user.PasswordHash))
{
return Unauthorized(ApiResponse<LoginResponseDto>.Error("Invalid email or password", 401));
}
// Check if user is active
if (user.Status != "Active")
{
return Unauthorized(ApiResponse<LoginResponseDto>.Error("User account is not active", 401));
}
// Update last login time
user.LastLoginAt = DateTime.UtcNow;
await _context.SaveChangesAsync();
// Generate token
var token = _tokenService.GenerateToken(user);
// Publish login event
await _daprClient.PublishEventAsync("pubsub", "user-login", new
{
userId = user.Id,
email = user.Email,
timestamp = DateTime.UtcNow
});
_logger.LogInformation("User logged in successfully: {Email}", user.Email);
var response = new LoginResponseDto
{
Token = token,
User = MapToUserDto(user)
};
return Ok(ApiResponse<LoginResponseDto>.Success(response));
}
catch (Exception ex)
{
_logger.LogError(ex, "Error during user login");
return StatusCode(500, ApiResponse<LoginResponseDto>.Error("Internal server error", 500));
}
}
[HttpGet("profile/{id}")]
public async Task<ActionResult<ApiResponse<UserDto>>> GetProfile(int id)
{
try
{
var user = await _context.Users.FindAsync(id);
if (user == null)
{
return NotFound(ApiResponse<UserDto>.Error("User not found", 404));
}
return Ok(ApiResponse<UserDto>.Success(MapToUserDto(user)));
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving user profile");
return StatusCode(500, ApiResponse<UserDto>.Error("Internal server error", 500));
}
}
[HttpPost("change-password/{id}")]
public async Task<ActionResult<ApiResponse<object>>> ChangePassword(int id, ChangePasswordDto changePasswordDto)
{
try
{
var user = await _context.Users.FindAsync(id);
if (user == null)
{
return NotFound(ApiResponse<object>.Error("User not found", 404));
}
// Verify current password
if (!_passwordHasher.VerifyPassword(changePasswordDto.CurrentPassword, user.PasswordHash))
{
return BadRequest(ApiResponse<object>.Error("Current password is incorrect", 400));
}
// Update password
user.PasswordHash = _passwordHasher.HashPassword(changePasswordDto.NewPassword);
await _context.SaveChangesAsync();
// Publish password changed event
await _daprClient.PublishEventAsync("pubsub", "user-password-changed", new
{
userId = user.Id,
email = user.Email,
timestamp = DateTime.UtcNow
});
_logger.LogInformation("Password changed successfully for user: {Email}", user.Email);
return Ok(ApiResponse<object>.Success(new { message = "Password changed successfully" }));
}
catch (Exception ex)
{
_logger.LogError(ex, "Error changing password");
return StatusCode(500, ApiResponse<object>.Error("Internal server error", 500));
}
}
private UserDto MapToUserDto(User user)
{
return new UserDto
{
Id = user.Id,
Name = user.Name,
Email = user.Email,
Role = user.Role,
Status = user.Status,
CreatedAt = user.CreatedAt,
LastLoginAt = user.LastLoginAt
};
}
}