using DomainObjects; using DataProviders.Collections; using DomainResults.Mvc; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using WeatherForecast.Models.Account.Requests; using WeatherForecast.Policies; using WeatherForecast.Services; using DomainObjects.Documents; namespace WeatherForecast.Controllers; /// /// /// [ApiController] [Route("api/[controller]")] public class AccountController : ControllerBase { private const string _password = "Password"; private readonly IAuthorizationService _authorizationService; private readonly IAccountService _accountService; private readonly IUserDataProvider _userDataProvider; /// /// /// public AccountController( IAuthorizationService authorizationService, IAccountService accountService, IUserDataProvider userDataProvider ) { _authorizationService = authorizationService; _accountService = accountService; _userDataProvider = userDataProvider; } #region Authless methods /// /// By providing username and password user obtains jwt token /// /// /// [HttpPost("[action]")] public IActionResult Authenticate([FromBody] AuthenticationRequestModel requestData) { var result = _accountService.Authenticate(requestData); return result.ToActionResult(); } [HttpPost("[action]")] public IActionResult Create() { return BadRequest(); } /// /// Passing the Username in the request body is a more secure alternative to passing it as a GET param /// /// /// /// [HttpPut($"{_password}/[action]")] public IActionResult Recovery([FromBody] PasswordRecoveryRequestModel requestData) { return BadRequest(); } /// /// When the form is submitted with the new password and the token as inputs the reset password process will take place. /// The form data will be sent with a PUT request again but this time including the token and we will replace the resource password with a new value /// /// /// /// [HttpPut($"{_password}/[action]")] public IActionResult Reset([FromBody] PasswordResetRequestModel requestData) { /// here we find user by token provided in requestData /// if ok we continue /// return Unauthorized(); } #endregion /// /// For authenticated users that want to change their password the PUT request can be performed immediately without the email /// (the account for which we are updating the password is known to the server). In such case the form will submit two fields /// /// /// /// [HttpPut($"{_password}/[action]/{{userId}}")] public async Task Change([FromRoute] Guid userId, [FromBody] PasswordChangeRequestModel requestData) { var (user, getUserResult) = _userDataProvider.Get(userId); if (!getUserResult.IsSuccess || user == null) return BadRequest(); if ((await _authorizationService.AuthorizeAsync(User, new List { user }, new PasswordChangeRequirement { OldPassword = requestData.OldPassword })).Succeeded) { var result = _accountService.PasswordChange(user, requestData.NewPassword); return result.ToActionResult(); } return Unauthorized(); } }