refactor(back): make code more declarative
This commit is contained in:
parent
a486bdfc80
commit
777c4b16b6
@ -1,9 +1,9 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Server.Services;
|
||||
using Server.Settings;
|
||||
using SharedModels.Requests;
|
||||
using SharedModels.Responses;
|
||||
|
||||
namespace Server.Controllers;
|
||||
|
||||
@ -21,29 +21,31 @@ public class AuthenticationController : ControllerBase
|
||||
}
|
||||
|
||||
[HttpPost("register")]
|
||||
public async Task<IActionResult> RegisterAsync([FromBody] RegistrationRequest model)
|
||||
public async Task<IActionResult> RegisterAsync([FromBody] RegistrationRequest registerRequest)
|
||||
{
|
||||
var result = await _authService.RegisterAsync(model);
|
||||
var (succeeded, message) =
|
||||
await _authService.RegisterAsync(registerRequest);
|
||||
|
||||
if (!result.succeeded)
|
||||
if (!succeeded)
|
||||
{
|
||||
return BadRequest(result.message);
|
||||
return BadRequest(new ResponseBase {Message = message});
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
return Ok(new ResponseBase{ Message = message });
|
||||
}
|
||||
|
||||
[HttpPost("authenticate")]
|
||||
public async Task<IActionResult> GetTokenAsync(AuthenticationRequest authRequest)
|
||||
{
|
||||
var authResponse = await _authService.AuthenticateAsync(authRequest);
|
||||
var (succeeded, authResponse, refreshToken) =
|
||||
await _authService.AuthenticateAsync(authRequest);
|
||||
|
||||
if (!authResponse.IsAuthenticated)
|
||||
if (!succeeded)
|
||||
{
|
||||
return BadRequest(authResponse);
|
||||
}
|
||||
|
||||
SetRefreshTokenInCookie(authResponse.RefreshToken);
|
||||
SetRefreshTokenInCookie(refreshToken!);
|
||||
|
||||
return Ok(authResponse);
|
||||
}
|
||||
@ -53,16 +55,17 @@ public class AuthenticationController : ControllerBase
|
||||
{
|
||||
var refreshToken = Request.Cookies["refreshToken"];
|
||||
|
||||
var authResponse = await _authService.RenewRefreshTokenAsync(refreshToken);
|
||||
var (succeeded, authResponse, newRefreshToken) =
|
||||
await _authService.RenewRefreshTokenAsync(refreshToken);
|
||||
|
||||
if (!authResponse.IsAuthenticated)
|
||||
if (!succeeded)
|
||||
{
|
||||
return BadRequest(authResponse);
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(authResponse.RefreshToken))
|
||||
if (!String.IsNullOrEmpty(newRefreshToken))
|
||||
{
|
||||
SetRefreshTokenInCookie(authResponse.RefreshToken);
|
||||
SetRefreshTokenInCookie(newRefreshToken);
|
||||
}
|
||||
|
||||
return Ok(authResponse);
|
||||
@ -72,19 +75,19 @@ public class AuthenticationController : ControllerBase
|
||||
public async Task<IActionResult> RevokeToken([FromBody] RevokeRefreshTokenRequest revokeRequest)
|
||||
{
|
||||
// accept token from request body or cookie
|
||||
var token = revokeRequest?.Token ?? Request.Cookies["refreshToken"];
|
||||
var token = revokeRequest.Token ?? Request.Cookies["refreshToken"];
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
return BadRequest(new { message = "Refresh token is required." });
|
||||
return BadRequest(new ResponseBase{ Message = "Refresh token is required." });
|
||||
}
|
||||
|
||||
var response = await _authService.RevokeRefreshToken(token);
|
||||
if (!response)
|
||||
{
|
||||
return NotFound(new { message = "Refresh token not found." });
|
||||
return NotFound(new ResponseBase{ Message = "Refresh token not found." });
|
||||
}
|
||||
|
||||
return Ok(new { message = "Refresh token revoked." });
|
||||
return Ok(new ResponseBase{ Message = "Refresh token revoked." });
|
||||
}
|
||||
|
||||
private void SetRefreshTokenInCookie(string refreshToken)
|
||||
|
@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SharedModels.Responses;
|
||||
|
||||
namespace Server.Controllers;
|
||||
|
||||
@ -11,6 +12,9 @@ public class SecuredController : ControllerBase
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetSecuredData()
|
||||
{
|
||||
return Ok("This Secured Data is available only for Authenticated Users with Admin role.");
|
||||
return Ok(new ResponseBase
|
||||
{
|
||||
Message = "This Secured Data is available only for Authenticated Users with Admin role."
|
||||
});
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ public class AuthenticationService : IAuthenticationService
|
||||
_jwt = jwt.Value;
|
||||
}
|
||||
|
||||
public async Task<(bool, string)> RegisterAsync(RegistrationRequest regRequest)
|
||||
public async Task<(bool succeeded, string message)> RegisterAsync(RegistrationRequest regRequest)
|
||||
{
|
||||
var userWithSameEmail = await _userManager.FindByEmailAsync(regRequest.Email);
|
||||
if (userWithSameEmail != null)
|
||||
@ -40,18 +40,17 @@ public class AuthenticationService : IAuthenticationService
|
||||
var user = new ApplicationUser {UserName = regRequest.Username, Email = regRequest.Email};
|
||||
|
||||
var result = await _userManager.CreateAsync(user, regRequest.Password);
|
||||
if (result.Succeeded)
|
||||
if (!result.Succeeded)
|
||||
{
|
||||
await _userManager.AddToRoleAsync(user, Authorization.DefaultRole.ToString());
|
||||
return (true, $"User registered with email {user.Email}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
return (false, $"{result.Errors?.First().Description}.");
|
||||
return (false, $"{result.Errors?.First().Description}");
|
||||
}
|
||||
|
||||
await _userManager.AddToRoleAsync(user, Authorization.DefaultRole.ToString());
|
||||
return (true, $"User registered with email {user.Email}.");
|
||||
}
|
||||
|
||||
public async Task<AuthenticationResponse> AuthenticateAsync(AuthenticationRequest authRequest)
|
||||
public async Task<(bool succeeded, AuthenticationResponse authResponse,
|
||||
string? refreshToken)> AuthenticateAsync(AuthenticationRequest authRequest)
|
||||
{
|
||||
var authResponse = new AuthenticationResponse();
|
||||
|
||||
@ -59,46 +58,42 @@ public class AuthenticationService : IAuthenticationService
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
authResponse.IsAuthenticated = false;
|
||||
authResponse.Message = $"No accounts registered with {authRequest.Email}.";
|
||||
return authResponse;
|
||||
return (false, authResponse, null);
|
||||
}
|
||||
|
||||
if (!await _userManager.CheckPasswordAsync(user, authRequest.Password))
|
||||
{
|
||||
authResponse.IsAuthenticated = false;
|
||||
authResponse.Message = $"Incorrect login or password.";
|
||||
return authResponse;
|
||||
return (false, authResponse, null);
|
||||
}
|
||||
|
||||
authResponse.IsAuthenticated = true;
|
||||
authResponse.Email = user.Email;
|
||||
authResponse.UserName = user.UserName;
|
||||
var roles = await _userManager.GetRolesAsync(user);
|
||||
authResponse.Roles = roles.ToList();
|
||||
var jwtSecurityToken = await CreateJwtToken(user);
|
||||
authResponse.Token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
|
||||
|
||||
string refreshTokenString;
|
||||
|
||||
if (user.RefreshTokens.Any(t => t.IsActive))
|
||||
{
|
||||
var activeRefreshToken =
|
||||
user.RefreshTokens.First(t => t.IsActive);
|
||||
authResponse.RefreshToken = activeRefreshToken.Token;
|
||||
authResponse.RefreshTokenExpiration = activeRefreshToken.Expires;
|
||||
refreshTokenString = activeRefreshToken.Token;
|
||||
authResponse.RefreshTokenExpirationDate = activeRefreshToken.Expires;
|
||||
}
|
||||
else
|
||||
{
|
||||
var refreshToken = CreateRefreshToken();
|
||||
authResponse.RefreshToken = refreshToken.Token;
|
||||
authResponse.RefreshTokenExpiration = refreshToken.Expires;
|
||||
refreshTokenString = refreshToken.Token;
|
||||
authResponse.RefreshTokenExpirationDate = refreshToken.Expires;
|
||||
user.RefreshTokens.Add(refreshToken);
|
||||
await _userManager.UpdateAsync(user);
|
||||
}
|
||||
|
||||
return authResponse;
|
||||
return (true, authResponse, refreshTokenString);
|
||||
}
|
||||
|
||||
public async Task<AuthenticationResponse> RenewRefreshTokenAsync(string? token)
|
||||
public async Task<(bool succeeded, AuthenticationResponse authResponse,
|
||||
string? refreshToken)> RenewRefreshTokenAsync(string? token)
|
||||
{
|
||||
var authResponse = new AuthenticationResponse();
|
||||
|
||||
@ -107,18 +102,16 @@ public class AuthenticationService : IAuthenticationService
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
authResponse.IsAuthenticated = false;
|
||||
authResponse.Message = "Refresh token did not mach any user.";
|
||||
return authResponse;
|
||||
return (false, authResponse, null);
|
||||
}
|
||||
|
||||
var refreshToken = user.RefreshTokens.Single(t => t.Token == token);
|
||||
|
||||
if (!refreshToken.IsActive)
|
||||
{
|
||||
authResponse.IsAuthenticated = false;
|
||||
authResponse.Message = "Refresh token expired.";
|
||||
return authResponse;
|
||||
return (false, authResponse, null);
|
||||
}
|
||||
|
||||
//Revoke Current Refresh Token
|
||||
@ -130,20 +123,12 @@ public class AuthenticationService : IAuthenticationService
|
||||
await _userManager.UpdateAsync(user);
|
||||
|
||||
//Generates new jwt
|
||||
authResponse.IsAuthenticated = true;
|
||||
authResponse.Email = user.Email;
|
||||
authResponse.UserName = user.UserName;
|
||||
|
||||
var roles = await _userManager.GetRolesAsync(user);
|
||||
authResponse.Roles = roles.ToList();
|
||||
|
||||
var jwtSecurityToken = await CreateJwtToken(user);
|
||||
authResponse.Token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
|
||||
|
||||
authResponse.RefreshToken = newRefreshToken.Token;
|
||||
authResponse.RefreshTokenExpiration = newRefreshToken.Expires;
|
||||
authResponse.RefreshTokenExpirationDate = newRefreshToken.Expires;
|
||||
|
||||
return authResponse;
|
||||
return (true, authResponse, newRefreshToken.Token);
|
||||
}
|
||||
|
||||
public async Task<bool> RevokeRefreshToken(string? token)
|
||||
@ -183,10 +168,10 @@ public class AuthenticationService : IAuthenticationService
|
||||
|
||||
var claims = new[]
|
||||
{
|
||||
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
|
||||
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
|
||||
new Claim(JwtRegisteredClaimNames.Email, user.Email),
|
||||
new Claim("uid", user.Id)
|
||||
new Claim("uid", user.Id),
|
||||
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
|
||||
new Claim(JwtRegisteredClaimNames.Email, user.Email)
|
||||
}
|
||||
.Union(userClaims)
|
||||
.Union(roleClaims);
|
||||
|
@ -8,9 +8,9 @@ public interface IAuthenticationService
|
||||
{
|
||||
Task<(bool succeeded, string message)> RegisterAsync(RegistrationRequest regRequest);
|
||||
|
||||
Task<AuthenticationResponse> AuthenticateAsync(AuthenticationRequest authRequest);
|
||||
Task<(bool succeeded, AuthenticationResponse authResponse, string? refreshToken)> AuthenticateAsync(AuthenticationRequest authRequest);
|
||||
|
||||
Task<AuthenticationResponse> RenewRefreshTokenAsync(string? token);
|
||||
Task<(bool succeeded, AuthenticationResponse authResponse, string? refreshToken)> RenewRefreshTokenAsync(string? token);
|
||||
|
||||
Task<bool> RevokeRefreshToken(string? token);
|
||||
}
|
@ -1,16 +1,7 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SharedModels.Responses;
|
||||
|
||||
public class AuthenticationResponse
|
||||
public class AuthenticationResponse : ResponseBase
|
||||
{
|
||||
public string Message { get; set; } = null!;
|
||||
public bool IsAuthenticated { get; set; }
|
||||
public string UserName { get; set; } = null!;
|
||||
public string Email { get; set; } = null!;
|
||||
public List<string> Roles { get; set; } = null!;
|
||||
public string Token { get; set; } = null!;
|
||||
[JsonIgnore]
|
||||
public string RefreshToken { get; set; } = null!;
|
||||
public DateTime RefreshTokenExpiration { get; set; }
|
||||
public string? Token { get; set; }
|
||||
public DateTime? RefreshTokenExpirationDate { get; set; }
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SharedModels.Responses;
|
||||
|
||||
public class ResponseBase
|
||||
{
|
||||
[JsonInclude]
|
||||
public string? Message;
|
||||
}
|
Loading…
Reference in New Issue
Block a user