351 lines
11 KiB
C#
351 lines
11 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
|
|
{
|
|
/// <summary>
|
|
/// 账户管理控制器
|
|
/// 处理用户注册、登录、密码重置等认证相关操作
|
|
/// </summary>
|
|
[Route("api/account")]
|
|
[ApiController]
|
|
public class AccountController : ControllerBase
|
|
{
|
|
private readonly UserManager<User> _userManager;
|
|
private readonly IUserRegistrationService _userRegistrationService;
|
|
private IAuthenticationService _authenticationService;
|
|
private readonly IEmailSender _emailSender;
|
|
|
|
/// <summary>
|
|
/// 初始化账户控制器
|
|
/// </summary>
|
|
/// <param name="userManager">用户管理服务</param>
|
|
/// <param name="userRegistrationService">用户注册服务</param>
|
|
/// <param name="emailSender">邮件发送服务</param>
|
|
/// <param name="authenticationService">认证服务</param>
|
|
public AccountController(UserManager<User> userManager,
|
|
IUserRegistrationService userRegistrationService,
|
|
IEmailSender emailSender,
|
|
IAuthenticationService authenticationService)
|
|
{
|
|
_userManager = userManager;
|
|
this._userRegistrationService = userRegistrationService;
|
|
_emailSender = emailSender;
|
|
_authenticationService = authenticationService;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 注册新用户
|
|
/// </summary>
|
|
/// <param name="userForRegistrationDto">用户注册信息数据传输对象</param>
|
|
/// <returns>注册结果响应</returns>
|
|
/// <response code="201">用户注册成功</response>
|
|
/// <response code="400">注册请求无效或验证失败</response>
|
|
[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
|
|
}
|
|
|
|
/// <summary>
|
|
/// 用户登录认证
|
|
/// </summary>
|
|
/// <param name="userForAuthentication">用户认证信息数据传输对象</param>
|
|
/// <returns>认证结果响应</returns>
|
|
/// <response code="200">登录成功,返回认证令牌</response>
|
|
/// <response code="401">认证失败,用户名或密码错误</response>
|
|
/// <response code="400">请求无效或验证失败</response>
|
|
[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
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 生成两步验证的OTP令牌
|
|
/// </summary>
|
|
/// <param name="user">用户对象</param>
|
|
/// <returns>两步验证响应</returns>
|
|
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"
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 忘记密码请求
|
|
/// 发送密码重置令牌到用户邮箱
|
|
/// </summary>
|
|
/// <param name="forgotPasswordDto">忘记密码请求数据传输对象</param>
|
|
/// <returns>操作结果</returns>
|
|
/// <response code="200">密码重置邮件发送成功</response>
|
|
/// <response code="400">请求无效或用户不存在</response>
|
|
[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();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 重置用户密码
|
|
/// </summary>
|
|
/// <param name="resetPasswordDto">密码重置数据传输对象</param>
|
|
/// <returns>重置结果响应</returns>
|
|
/// <response code="200">密码重置成功</response>
|
|
/// <response code="400">密码重置失败</response>
|
|
[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});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 邮箱确认验证
|
|
/// 验证用户邮箱确认令牌
|
|
/// </summary>
|
|
/// <param name="email">用户邮箱地址</param>
|
|
/// <param name="token">邮箱确认令牌</param>
|
|
/// <returns>验证结果</returns>
|
|
/// <response code="200">邮箱确认成功</response>
|
|
/// <response code="400">邮箱确认失败</response>
|
|
[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();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 两步验证确认
|
|
/// 验证用户提供的两步验证令牌
|
|
/// </summary>
|
|
/// <param name="twoFactorVerificationDto">两步验证数据传输对象</param>
|
|
/// <returns>验证结果响应</returns>
|
|
/// <response code="200">验证成功,返回认证令牌</response>
|
|
/// <response code="400">验证失败</response>
|
|
[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
|
|
});
|
|
}
|
|
}
|
|
}
|