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 _userManager; private readonly IUserRegistrationService _userRegistrationService; private IAuthenticationService _authenticationService; private readonly IEmailSender _emailSender; public AccountController(UserManager userManager, IUserRegistrationService userRegistrationService, IEmailSender emailSender, IAuthenticationService authenticationService) { _userManager = userManager; this._userRegistrationService = userRegistrationService; _emailSender = emailSender; _authenticationService = authenticationService; } [HttpPost("register")] public async Task 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 //{ // {"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 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 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 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 { {"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 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 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 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 }); } } }