refactor(back): make code more declarative

This commit is contained in:
cuqmbr 2022-09-06 10:09:52 +03:00
parent a486bdfc80
commit 777c4b16b6
6 changed files with 65 additions and 73 deletions

View File

@ -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)

View File

@ -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."
});
}
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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; }
}

View File

@ -0,0 +1,9 @@
using System.Text.Json.Serialization;
namespace SharedModels.Responses;
public class ResponseBase
{
[JsonInclude]
public string? Message;
}