You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

473 lines
17 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Haoliang.Core.Services;
using Haoliang.Models.User;
using Haoliang.Models.Common;
namespace Haoliang.Api.Controllers
{
[ApiController]
[Route("api/v1/[controller]")]
public class AuthController : ControllerBase
{
private readonly IAuthService _authService;
private readonly IUserService _userService;
private readonly IPermissionService _permissionService;
private readonly ILoggingService _loggingService;
public AuthController(
IAuthService authService,
IUserService userService,
IPermissionService permissionService,
ILoggingService loggingService)
{
_authService = authService;
_userService = userService;
_permissionService = permissionService;
_loggingService = loggingService;
}
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LoginRequest request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(ApiResponse<AuthResult>.Error("Invalid request data", 400));
}
var result = await _authService.LoginAsync(request);
if (result.Success)
{
await _loggingService.LogInformationAsync($"User {request.Username} logged in successfully");
return Ok(ApiResponse<AuthResult>.Success(result));
}
else
{
await _loggingService.LogWarningAsync($"Failed login attempt for user {request.Username}");
return Unauthorized(ApiResponse<AuthResult>.Error("Invalid username or password", 401));
}
}
catch (Exception ex)
{
await _loggingService.LogErrorAsync($"Login error for user {request.Username}: {ex.Message}", ex);
return StatusCode(500, ApiResponse<AuthResult>.Error("Internal server error", 500));
}
}
[HttpPost("logout")]
public async Task<IActionResult> Logout([FromBody] LogoutRequest request)
{
try
{
if (request?.UserId == null)
{
return BadRequest(ApiResponse<bool>.Error("User ID is required", 400));
}
var success = await _authService.LogoutAsync(request.UserId.Value);
if (success)
{
await _loggingService.LogInformationAsync($"User {request.UserId} logged out successfully");
return Ok(ApiResponse<bool>.Success(true));
}
else
{
return BadRequest(ApiResponse<bool>.Error("Logout failed", 400));
}
}
catch (Exception ex)
{
await _loggingService.LogErrorAsync($"Logout error: {ex.Message}", ex);
return StatusCode(500, ApiResponse<bool>.Error("Internal server error", 500));
}
}
[HttpPost("refresh")]
public async Task<IActionResult> RefreshToken([FromBody] RefreshTokenRequest request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(ApiResponse<AuthResult>.Error("Invalid request data", 400));
}
var result = await _authService.RefreshTokenAsync(request.RefreshToken);
if (result.Success)
{
return Ok(ApiResponse<AuthResult>.Success(result));
}
else
{
return Unauthorized(ApiResponse<AuthResult>.Error("Invalid refresh token", 401));
}
}
catch (Exception ex)
{
await _loggingService.LogErrorAsync($"Token refresh error: {ex.Message}", ex);
return StatusCode(500, ApiResponse<AuthResult>.Error("Internal server error", 500));
}
}
[HttpPost("register")]
public async Task<IActionResult> Register([FromBody] RegisterRequest request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(ApiResponse<UserViewModel>.Error("Invalid request data", 400));
}
// Check if username already exists
var usernameExists = await _authService.UsernameExistsAsync(request.Username);
if (usernameExists)
{
return BadRequest(ApiResponse<UserViewModel>.Error("Username already exists", 400));
}
// Check if email already exists
var emailExists = await _authService.EmailExistsAsync(request.Email);
if (emailExists)
{
return BadRequest(ApiResponse<UserViewModel>.Error("Email already exists", 400));
}
// Create user
var user = new User
{
Username = request.Username,
Email = request.Email,
PasswordHash = BCrypt.Net.BCrypt.HashPassword(request.Password),
FirstName = request.FirstName,
LastName = request.LastName,
Department = request.Department,
IsActive = true,
CreatedAt = DateTime.Now,
UpdatedAt = DateTime.Now
};
var userViewModel = await _userService.CreateUserAsync(user);
await _loggingService.LogInformationAsync($"New user registered: {request.Username}");
return Ok(ApiResponse<UserViewModel>.Success(userViewModel));
}
catch (Exception ex)
{
await _loggingService.LogErrorAsync($"Registration error for user {request.Username}: {ex.Message}", ex);
return StatusCode(500, ApiResponse<UserViewModel>.Error("Internal server error", 500));
}
}
[HttpGet("profile")]
public async Task<IActionResult> GetProfile()
{
try
{
// Get user ID from claims (in real implementation, use JWT token validation)
var userId = GetCurrentUserId();
if (userId == null)
{
return Unauthorized(ApiResponse<UserViewModel>.Error("Not authenticated", 401));
}
var user = await _userService.GetUserByIdAsync(userId.Value);
if (user == null)
{
return NotFound(ApiResponse<UserViewModel>.Error("User not found", 404));
}
return Ok(ApiResponse<UserViewModel>.Success(user));
}
catch (Exception ex)
{
await _loggingService.LogErrorAsync($"Profile fetch error: {ex.Message}", ex);
return StatusCode(500, ApiResponse<UserViewModel>.Error("Internal server error", 500));
}
}
[HttpPut("profile")]
public async Task<IActionResult> UpdateProfile([FromBody] UpdateUserProfileRequest request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(ApiResponse<UserViewModel>.Error("Invalid request data", 400));
}
var userId = GetCurrentUserId();
if (userId == null)
{
return Unauthorized(ApiResponse<UserViewModel>.Error("Not authenticated", 401));
}
var user = new User
{
Username = request.Username,
Email = request.Email,
FirstName = request.FirstName,
LastName = request.LastName,
Department = request.Department,
UpdatedAt = DateTime.Now
};
var updatedUser = await _userService.UpdateUserAsync(userId.Value, user);
await _loggingService.LogInformationAsync($"User profile updated: {request.Username}");
return Ok(ApiResponse<UserViewModel>.Success(updatedUser));
}
catch (Exception ex)
{
await _loggingService.LogErrorAsync($"Profile update error: {ex.Message}", ex);
return StatusCode(500, ApiResponse<UserViewModel>.Error("Internal server error", 500));
}
}
[HttpPost("change-password")]
public async Task<IActionResult> ChangePassword([FromBody] ChangePasswordRequest request)
{
try
{
if (!ModelState.IsValid)
{
return BadRequest(ApiResponse<bool>.Error("Invalid request data", 400));
}
var userId = GetCurrentUserId();
if (userId == null)
{
return Unauthorized(ApiResponse<bool>.Error("Not authenticated", 401));
}
var success = await _userService.ChangePasswordAsync(
userId.Value,
request.OldPassword,
request.NewPassword);
if (success)
{
await _loggingService.LogInformationAsync($"Password changed for user: {userId}");
return Ok(ApiResponse<bool>.Success(true));
}
else
{
return BadRequest(ApiResponse<bool>.Error("Invalid old password", 400));
}
}
catch (Exception ex)
{
await _loggingService.LogErrorAsync($"Password change error: {ex.Message}", ex);
return StatusCode(500, ApiResponse<bool>.Error("Internal server error", 500));
}
}
[HttpGet("permissions")]
public async Task<IActionResult> GetUserPermissions()
{
try
{
var userId = GetCurrentUserId();
if (userId == null)
{
return Unauthorized(ApiResponse<IEnumerable<string>>.Error("Not authenticated", 401));
}
var permissions = await _permissionService.GetUserPermissionsAsync(userId.Value);
return Ok(ApiResponse<IEnumerable<string>>.Success(permissions));
}
catch (Exception ex)
{
await _loggingService.LogErrorAsync($"Permission fetch error: {ex.Message}", ex);
return StatusCode(500, ApiResponse<IEnumerable<string>>.Error("Internal server error", 500));
}
}
[HttpGet("users")]
[ProducesResponseType(typeof(PaginatedResponse<UserViewModel>), 200)]
public async Task<IActionResult> GetAllUsers([FromQuery] UserFilter filter)
{
try
{
var users = await _userService.GetAllUsersAsync();
// Apply filters
if (!string.IsNullOrEmpty(filter.Role))
{
users = users.Where(u => u.Role == filter.Role);
}
if (!string.IsNullOrEmpty(filter.Department))
{
users = users.Where(u => u.Department == filter.Department);
}
if (filter.IsActive.HasValue)
{
users = users.Where(u => u.IsActive == filter.IsActive.Value);
}
var totalCount = users.Count();
// Apply pagination
var pagedUsers = users
.Skip((filter.PageNumber - 1) * filter.PageSize)
.Take(filter.PageSize)
.ToList();
var response = new PaginatedResponse<UserViewModel>
{
Items = pagedUsers,
TotalCount = totalCount,
PageNumber = filter.PageNumber,
PageSize = filter.PageSize,
TotalPages = (int)Math.Ceiling((double)totalCount / filter.PageSize),
HasPreviousPage = filter.PageNumber > 1,
HasNextPage = filter.PageNumber < (int)Math.Ceiling((double)totalCount / filter.PageSize)
};
return Ok(response);
}
catch (Exception ex)
{
await _loggingService.LogErrorAsync($"Users fetch error: {ex.Message}", ex);
return StatusCode(500, ApiResponse<PaginatedResponse<UserViewModel>>.Error("Internal server error", 500));
}
}
[HttpGet("users/{id}")]
public async Task<IActionResult> GetUserById(int id)
{
try
{
var user = await _userService.GetUserByIdAsync(id);
if (user == null)
{
return NotFound(ApiResponse<UserViewModel>.Error("User not found", 404));
}
return Ok(ApiResponse<UserViewModel>.Success(user));
}
catch (Exception ex)
{
await _loggingService.LogErrorAsync($"User fetch error for ID {id}: {ex.Message}", ex);
return StatusCode(500, ApiResponse<UserViewModel>.Error("Internal server error", 500));
}
}
[HttpPost("users/{id}/activate")]
public async Task<IActionResult> ActivateUser(int id)
{
try
{
var success = await _userService.ActivateUserAsync(id);
if (success)
{
await _loggingService.LogInformationAsync($"User activated: {id}");
return Ok(ApiResponse<bool>.Success(true));
}
else
{
return BadRequest(ApiResponse<bool>.Error("Failed to activate user", 400));
}
}
catch (Exception ex)
{
await _loggingService.LogErrorAsync($"User activation error for ID {id}: {ex.Message}", ex);
return StatusCode(500, ApiResponse<bool>.Error("Internal server error", 500));
}
}
[HttpPost("users/{id}/deactivate")]
public async Task<IActionResult> DeactivateUser(int id)
{
try
{
var success = await _userService.DeactivateUserAsync(id);
if (success)
{
await _loggingService.LogInformationAsync($"User deactivated: {id}");
return Ok(ApiResponse<bool>.Success(true));
}
else
{
return BadRequest(ApiResponse<bool>.Error("Failed to deactivate user", 400));
}
}
catch (Exception ex)
{
await _loggingService.LogErrorAsync($"User deactivation error for ID {id}: {ex.Message}", ex);
return StatusCode(500, ApiResponse<bool>.Error("Internal server error", 500));
}
}
private int? GetCurrentUserId()
{
// In a real implementation, extract user ID from JWT token claims
// For now, return null (would be implemented in JWT middleware)
return null;
}
}
// Supporting request and response models
public class LoginRequest
{
public string Username { get; set; }
public string Password { get; set; }
public bool RememberMe { get; set; }
}
public class LogoutRequest
{
public int UserId { get; set; }
}
public class RefreshTokenRequest
{
public string RefreshToken { get; set; }
}
public class RegisterRequest
{
public string Username { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Department { get; set; }
}
public class UpdateUserProfileRequest
{
public string Username { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Department { get; set; }
}
public class ChangePasswordRequest
{
public string OldPassword { get; set; }
public string NewPassword { get; set; }
public string ConfirmPassword { get; set; }
}
public class UserFilter
{
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 10;
public string Role { get; set; }
public string Department { get; set; }
public bool? IsActive { get; set; }
}
}