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 }); } /// /// 生成两步验证的OTP令牌 /// /// 用户对象 /// 两步验证响应 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 }); } } }