Files
TechHelper/TechHelper.Server/Controllers/AccountController.cs
2025-05-23 19:03:00 +08:00

288 lines
8.1 KiB
C#

using TechHelper.Context;
using TechHelper.Services;
using Entities.DTO;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using TechHelper.Features;
using Microsoft.AspNetCore.WebUtilities;
using Entities.Contracts;
namespace TechHelper.Controllers
{
[Route("api/account")]
[ApiController]
public class AccountController : ControllerBase
{
private readonly UserManager<User> _userManager;
private readonly IUserRegistrationService _userRegistrationService;
private IAuthenticationService _authenticationService;
private readonly IEmailSender _emailSender;
public AccountController(UserManager<User> userManager,
IUserRegistrationService userRegistrationService,
IEmailSender emailSender,
IAuthenticationService authenticationService)
{
_userManager = userManager;
this._userRegistrationService = userRegistrationService;
_emailSender = emailSender;
_authenticationService = authenticationService;
}
[HttpPost("register")]
public async Task<IActionResult> RegisterUsesr(
[FromBody] UserForRegistrationDto userForRegistrationDto)
{
#region V1
//if (userForRegistrationDto == null || !ModelState.IsValid)
// return BadRequest();
//var user = new User
//{
// UserName = userForRegistrationDto.Name,
// Email = userForRegistrationDto.Email,
// PhoneNumber = userForRegistrationDto.PhoneNumber,
// Address = userForRegistrationDto.HomeAddress
//};
//var result = await _userManager.CreateAsync(user, userForRegistrationDto.Password);
//if (!result.Succeeded)
//{
// var errors = result.Errors.Select(e => e.Description);
// return BadRequest(new ResponseDto { Errors = errors });
//}
//await _userManager.SetTwoFactorEnabledAsync(user, true);
//var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
//var param = new Dictionary<string, string>
//{
// {"token", token},
// {"email", userForRegistrationDto.Email}
//};
//var callback = QueryHelpers.AddQueryString(userForRegistrationDto.ClientURI, param);
//try
//{
// await _emailSender.SendEmailAsync(user.Email.ToString(), "Email Confirmation token", callback);
//}
//catch (Exception ex)
//{
//}
//await _userManager.AddToRoleAsync(user, userForRegistrationDto.Roles.ToString());
//return StatusCode(201);
#endregion
#region V2
if (!ModelState.IsValid)
return BadRequest(new ApiResponse(false, ModelState));
var response = await _userRegistrationService.RegisterNewUserAsync(userForRegistrationDto);
if (response.Status)
{
return StatusCode(201, response);
}
else
{
return BadRequest(response);
}
#endregion
}
[HttpPost("login")]
public async Task<IActionResult> Logion(
[FromBody] UserForAuthenticationDto userForAuthentication)
{
var user = await _userManager.FindByEmailAsync(userForAuthentication.Email);
if (user == null )
{
return Unauthorized(new AuthResponseDto
{
ErrorMessage = "Invalid Request"
});
}
//if(!await _userManager.IsEmailConfirmedAsync(user))
// return Unauthorized(new AuthResponseDto
// {
// ErrorMessage = "Email is not confirmed"
// });
if(await _userManager.IsLockedOutAsync(user))
return Unauthorized(new AuthResponseDto
{
ErrorMessage = "This account is locked out"
});
if (!await _userManager.CheckPasswordAsync(user,
userForAuthentication.Password))
{
await _userManager.AccessFailedAsync(user);
if(await _userManager.IsLockedOutAsync(user))
{
var content = $"Your account is locked out."
+ $"if you want to reset the password, you can use Forgot password link On the login page";
await _emailSender.SendEmailAsync(user.Email, "Locked out account information" ,content );
}
return Unauthorized(new AuthResponseDto
{
ErrorMessage = "Invalid Authentication"
});
}
if(await _userManager.GetTwoFactorEnabledAsync(user))
return await GenerateOTPFor2StepVerification(user);
var token = await _authenticationService.GetToken(user);
user.RefreshToken = _authenticationService.GenerateRefreshToken();
user.RefreshTokenExpiryTime = DateTime.Now.AddDays(7);
await _userManager.UpdateAsync(user);
await _userManager.ResetAccessFailedCountAsync(user);
return Ok(new AuthResponseDto
{
IsAuthSuccessful = true,
Token = token,
RefreshToken = user.RefreshToken
});
}
private async Task<IActionResult> GenerateOTPFor2StepVerification(User user)
{
var providers = await _userManager.GetValidTwoFactorProvidersAsync(user);
if(!providers.Contains("Email"))
{
return Unauthorized(new AuthResponseDto
{
ErrorMessage = "Invalid 2-Step verification Provider"
});
}
var token = await _userManager.GenerateTwoFactorTokenAsync(user, "Email");
await _emailSender.SendEmailAsync(user.Email, "Authentication token", token);
return Ok(new AuthResponseDto
{
Is2StepVerificationRequired = true,
Provider = "Email"
});
}
[HttpPost("forgotPassword")]
public async Task<IActionResult> ForgotPassword(
[FromBody] ForgotPasswordDto forgotPasswordDto)
{
var user = await _userManager.FindByEmailAsync(forgotPasswordDto.Email);
if (user == null)
return BadRequest("Invalid Request");
var token = await _userManager.GeneratePasswordResetTokenAsync(user);
var param = new Dictionary<string, string>
{
{"token", token},
{"email", forgotPasswordDto.Email}
};
var callback = QueryHelpers.AddQueryString(forgotPasswordDto.ClientURI, param);
await _emailSender.SendEmailAsync( user.Email.ToString() , "Reset Password Token", callback);
return Ok();
}
[HttpPost("resetPassword")]
public async Task<IActionResult> ResetPassword(
[FromBody] ResetPasswordDto resetPasswordDto)
{
var errorResponse = new ResetPasswordResponseDto
{
Errors = new string[] { "Reset Password Failed" }
};
if (!ModelState.IsValid)
return BadRequest(errorResponse);
var user = await _userManager.FindByEmailAsync(resetPasswordDto.Email);
if (user == null) return BadRequest(errorResponse);
var resetPassResult = await _userManager.ResetPasswordAsync(user,
resetPasswordDto.Token, resetPasswordDto.Password);
if (!resetPassResult.Succeeded)
{
var errors = resetPassResult.Errors.Select(e => e.Description);
return BadRequest(new ResetPasswordResponseDto { Errors = errors });
}
await _userManager.SetLockoutEndDateAsync(user, null);
return Ok(new ResetPasswordResponseDto { IsResetPasswordSuccessful = true});
}
[HttpGet("emailconfirmation")]
public async Task<IActionResult> EmailConfirmaation([FromQuery] string email,
[FromQuery] string token)
{
var user = await _userManager.FindByEmailAsync(email);
if (user == null) return BadRequest();
var confimResult = await _userManager.ConfirmEmailAsync(user, token);
if (!confimResult.Succeeded) return BadRequest();
return Ok();
}
[HttpPost("TwoStepVerification")]
public async Task<IActionResult> TwoStepVerification(
[FromBody] TwoFactorVerificationDto twoFactorVerificationDto)
{
if(!ModelState.IsValid) return BadRequest(
new AuthResponseDto
{
ErrorMessage = "Invalid Request"
});
var user = await _userManager.FindByEmailAsync(twoFactorVerificationDto.Email);
if(user == null) return BadRequest(
new AuthResponseDto
{
ErrorMessage = "Invalid Request"
});
var validVerification = await _userManager.VerifyTwoFactorTokenAsync(user, twoFactorVerificationDto.Provider, twoFactorVerificationDto.TwoFactorToken);
if(!validVerification) return BadRequest(
new AuthResponseDto
{
ErrorMessage = "Invalid Request"
});
var token = await _authenticationService.GetToken(user);
user.RefreshToken = _authenticationService.GenerateRefreshToken();
user.RefreshTokenExpiryTime = DateTime.Now.AddDays(7);
await _userManager.UpdateAsync(user);
await _userManager.ResetAccessFailedCountAsync(user);
return Ok(new AuthResponseDto
{
IsAuthSuccessful = true,
Token = token,
RefreshToken = user.RefreshToken
});
}
}
}