218 lines
7.2 KiB
C#
218 lines
7.2 KiB
C#
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
|
|
};
|
|
}
|
|
}
|