From 757e39fb770d58a91619f426832d1418c4a20c7d Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Mon, 15 Aug 2022 16:34:53 +0500 Subject: [PATCH 01/34] chore: #60: adds jwt token validator --- .../Contract/IJwtTokenValidator.cs | 7 ++++ .../Contract/JwtTokenValidator.cs | 34 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 JwtAuthentication.Core/Contract/IJwtTokenValidator.cs create mode 100644 JwtAuthentication.Core/Contract/JwtTokenValidator.cs diff --git a/JwtAuthentication.Core/Contract/IJwtTokenValidator.cs b/JwtAuthentication.Core/Contract/IJwtTokenValidator.cs new file mode 100644 index 0000000..667cf65 --- /dev/null +++ b/JwtAuthentication.Core/Contract/IJwtTokenValidator.cs @@ -0,0 +1,7 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract +{ + internal interface IJwtTokenValidator + { + void Validate(string jwtToken); + } +} diff --git a/JwtAuthentication.Core/Contract/JwtTokenValidator.cs b/JwtAuthentication.Core/Contract/JwtTokenValidator.cs new file mode 100644 index 0000000..de4ef15 --- /dev/null +++ b/JwtAuthentication.Core/Contract/JwtTokenValidator.cs @@ -0,0 +1,34 @@ +using Microsoft.IdentityModel.Tokens; +using System; +using System.IdentityModel.Tokens.Jwt; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Signing; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract +{ + internal class JwtTokenValidator : IJwtTokenValidator + { + private readonly AuthenticationOptions _authenticationOptions; + + public JwtTokenValidator(AuthenticationOptions options) + { + _authenticationOptions = options; + } + + public void Validate(string jwtTokenValue) + { + var handler = new JwtSecurityTokenHandler(); + var tokenValidationParameters = new TokenValidationParameters + { + ValidateLifetime = true, + ValidateIssuer = false, + ValidateAudience = false, + ValidateIssuerSigningKey = true, + IssuerSigningKey = SigningHelper.GetPublicKey(_authenticationOptions.PublicSigningKey), + ClockSkew = TimeSpan.Zero, + }; + + handler.ValidateToken(jwtTokenValue, tokenValidationParameters, out var _); + } + } +} From 65c7b0cb4aa2479c5ef0f99398690a61499370ab Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Mon, 15 Aug 2022 16:35:20 +0500 Subject: [PATCH 02/34] test(units): #60: adds jwt token validator tests --- .../Tests/Units/JwtTokenValidatorTests.cs | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Examples/Tests/Units/JwtTokenValidatorTests.cs diff --git a/Examples/Tests/Units/JwtTokenValidatorTests.cs b/Examples/Tests/Units/JwtTokenValidatorTests.cs new file mode 100644 index 0000000..634cfc4 --- /dev/null +++ b/Examples/Tests/Units/JwtTokenValidatorTests.cs @@ -0,0 +1,38 @@ +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; +using Xunit; + +namespace Tests.Units; + +public class JwtTokenValidatorTests +{ + private readonly JwtTokenValidator _jwtTokenValidator; + + private const string PublicSigningKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQAB"; + private const string ValidJwtToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IkFkbWluIiwiZXhwIjoxOTc1OTIyNzg5fQ.oOU4-XE1dCyVtViamBU5BgLy9x24LrcAV4cTUB_rwgdzLvyVuL2FdvEIBAsDR-uZwzaWC4VOGWYxjOVgu-Qvr2Td4sx-6p5DLJhrycsPFSrs4qU62wC4qRtCA-7s-hrumVh_fxh04UCC00crXvZUXnyHfAxC4nKIKiNAaLZ_inM3I8TYRuyBtOt-m0-K17qs5n-NMh_7lw_nBFB76pi1LuOUW6WDGV1bVfzSVD1daCaUc33pX5RQGeYsE-BlHPgTp5trueVz79-Kn1MtXYx_Xf-ltr7wGKWy1dLNNJoZewqDq-I0zqApDfmaO6Gy8xgZAykBx529DGj5KlMLx29yoQ"; + private const string InvalidJwtToken = "abJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IkFkbWluIiwiZXhwIjoxOTc1OTIyNzg5fQ.oOU4-XE1dCyVtViamBU5BgLy9x24LrcAV4cTUB_rwgdzLvyVuL2FdvEIBAsDR-uZwzaWC4VOGWYxjOVgu-Qvr2Td4sx-6p5DLJhrycsPFSrs4qU62wC4qRtCA-7s-hrumVh_fxh04UCC00crXvZUXnyHfAxC4nKIKiNAaLZ_inM3I8TYRuyBtOt-m0-K17qs5n-NMh_7lw_nBFB76pi1LuOUW6WDGV1bVfzSVD1daCaUc33pX5RQGeYsE-BlHPgTp5trueVz79-Kn1MtXYx_Xf-ltr7wGKWy1dLNNJoZewqDq-I0zqApDfmaO6Gy8xgZAykBx529DGj5KlMLx29yoQ"; + + public JwtTokenValidatorTests() + { + var authenticationOptions = new AuthenticationOptions() + { + PublicSigningKey = PublicSigningKey + }; + + _jwtTokenValidator = new JwtTokenValidator(authenticationOptions); + } + + [Fact] + public void ValidateJwtToken_TokenIsValid_NoExceptions() + { + var exception = Record.Exception(() => _jwtTokenValidator.Validate(ValidJwtToken)); + Assert.Null(exception); + } + + [Fact] + public void ValidateJwtToken_TokenIsInvalid_CatchExceptions() + { + var exception = Record.Exception(() => _jwtTokenValidator.Validate(InvalidJwtToken)); + Assert.NotNull(exception); + } +} \ No newline at end of file From 220031e595ebe4cc9628632ceaa5a4a2d62de07a Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Mon, 15 Aug 2022 16:56:53 +0500 Subject: [PATCH 03/34] chore: #60: corrects contract for access token generation --- JwtAuthentication.Core/Services/ITokenManager.cs | 2 +- .../Services/Implementation/LoginService.cs | 2 +- .../Services/Implementation/TokenManager.cs | 9 +++++++-- .../Services/IdentityLoginService.cs | 2 +- .../Services/RefreshSignInManager.cs | 2 +- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/JwtAuthentication.Core/Services/ITokenManager.cs b/JwtAuthentication.Core/Services/ITokenManager.cs index a3cd451..4fc6af8 100644 --- a/JwtAuthentication.Core/Services/ITokenManager.cs +++ b/JwtAuthentication.Core/Services/ITokenManager.cs @@ -5,6 +5,6 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services { internal interface ITokenManager { - Task GetAccessToken(string login); + Task GenerateAccessTokenAsync(string login = null); } } \ No newline at end of file diff --git a/JwtAuthentication.Core/Services/Implementation/LoginService.cs b/JwtAuthentication.Core/Services/Implementation/LoginService.cs index a186288..8cc9e35 100644 --- a/JwtAuthentication.Core/Services/Implementation/LoginService.cs +++ b/JwtAuthentication.Core/Services/Implementation/LoginService.cs @@ -31,7 +31,7 @@ public async Task LoginAsync(LoginRequestModel model) throw new AuthenticationException(ErrorTypes.IncorrectLoginOrPassword); } - var token = await _tokenManager.GetAccessToken(model.Login); + var token = await _tokenManager.GenerateAccessTokenAsync(model.Login); return new AuthResponseModel { diff --git a/JwtAuthentication.Core/Services/Implementation/TokenManager.cs b/JwtAuthentication.Core/Services/Implementation/TokenManager.cs index 1dcaf31..8f08cc1 100644 --- a/JwtAuthentication.Core/Services/Implementation/TokenManager.cs +++ b/JwtAuthentication.Core/Services/Implementation/TokenManager.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; using System.Runtime.CompilerServices; +using System.Security.Claims; using System.Threading.Tasks; using Microsoft.IdentityModel.Tokens; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; @@ -25,9 +27,12 @@ public TokenManager( _userClaimsProvider = userClaimsProvider; } - public async Task GetAccessToken(string login) + public async Task GenerateAccessTokenAsync(string login = null) { - var claims = await _userClaimsProvider.GetUserClaimsAsync(login); + var claims = login == null + ? new List() + : await _userClaimsProvider.GetUserClaimsAsync(login); + var privateKey = SigningHelper.GetPrivateKey(_options.PrivateSigningKey); var credentials = new SigningCredentials(privateKey, SecurityAlgorithms.RsaSha256); var expires = DateTime.UtcNow.AddMinutes(_options.AccessTokenExpireInMinutes); diff --git a/JwtAuthentication.Identity/Services/IdentityLoginService.cs b/JwtAuthentication.Identity/Services/IdentityLoginService.cs index f8954a4..f2ccee4 100644 --- a/JwtAuthentication.Identity/Services/IdentityLoginService.cs +++ b/JwtAuthentication.Identity/Services/IdentityLoginService.cs @@ -47,7 +47,7 @@ public async Task LoginAsync(LoginRequestModel model) throw new AuthenticationException(ErrorTypes.IncorrectLoginOrPassword); } - var token = await _tokenManager.GetAccessToken( + var token = await _tokenManager.GenerateAccessTokenAsync( model.Login ); diff --git a/JwtAuthentication.Identity/Services/RefreshSignInManager.cs b/JwtAuthentication.Identity/Services/RefreshSignInManager.cs index 506399b..b386cb1 100644 --- a/JwtAuthentication.Identity/Services/RefreshSignInManager.cs +++ b/JwtAuthentication.Identity/Services/RefreshSignInManager.cs @@ -69,7 +69,7 @@ public async Task GenerateAuthTokens(TUser appUser, string cl { return new AuthResponseModel { - AccessToken = await _accessTokenManager.GetAccessToken(appUser.NormalizedUserName), + AccessToken = await _accessTokenManager.GenerateAccessTokenAsync(appUser.NormalizedUserName), RefreshToken = await _refreshTokenManager.GenerateRefreshTokenAsync(appUser, clientFingerPrint), }; } From 19b448af2135ee2ad228d08a6669e34c6be65efc Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Mon, 15 Aug 2022 16:57:25 +0500 Subject: [PATCH 04/34] chore: #60: adds refresh servie for the core package --- .../ErrorHandling/ErrorTypes.cs | 3 +- .../Services/ICoreRefreshService.cs | 10 ++++++ .../Services/Implementation/RefreshService.cs | 36 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 JwtAuthentication.Core/Services/ICoreRefreshService.cs create mode 100644 JwtAuthentication.Core/Services/Implementation/RefreshService.cs diff --git a/JwtAuthentication.Core/ErrorHandling/ErrorTypes.cs b/JwtAuthentication.Core/ErrorHandling/ErrorTypes.cs index 885b98c..596456d 100644 --- a/JwtAuthentication.Core/ErrorHandling/ErrorTypes.cs +++ b/JwtAuthentication.Core/ErrorHandling/ErrorTypes.cs @@ -11,6 +11,7 @@ public enum ErrorTypes UserNotFound, ReCaptchaTokenIncorrect, RefreshTokenOrFingerprintNotFound, - RefreshTokenIsNotInConfidenceInterval, + RefreshTokenIsNotInConfidenceInterval, + InvalidJwtToken, } } \ No newline at end of file diff --git a/JwtAuthentication.Core/Services/ICoreRefreshService.cs b/JwtAuthentication.Core/Services/ICoreRefreshService.cs new file mode 100644 index 0000000..d31306a --- /dev/null +++ b/JwtAuthentication.Core/Services/ICoreRefreshService.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services +{ + internal interface ICoreRefreshService + { + public Task RefreshAsync(string jwtRefreshToken); + } +} \ No newline at end of file diff --git a/JwtAuthentication.Core/Services/Implementation/RefreshService.cs b/JwtAuthentication.Core/Services/Implementation/RefreshService.cs new file mode 100644 index 0000000..a5ac5f1 --- /dev/null +++ b/JwtAuthentication.Core/Services/Implementation/RefreshService.cs @@ -0,0 +1,36 @@ +using System; +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation +{ + internal class RefreshService : ICoreRefreshService + { + private readonly ITokenManager _tokenManager; + private readonly IJwtTokenValidator _jwtTokenValidator; + + public RefreshService( + ITokenManager tokenManager, + IJwtTokenValidator jwtTokenValidator) + { + _tokenManager = tokenManager; + _jwtTokenValidator = jwtTokenValidator; + } + + public async Task RefreshAsync(string jwtRefreshToken) + { + try + { + _jwtTokenValidator.Validate(jwtRefreshToken); + + return await _tokenManager.GenerateAccessTokenAsync(); + } + catch (Exception) + { + throw new AuthenticationException(ErrorTypes.InvalidJwtToken); + } + } + } +} From f9bebc23b440ed93b64a99187478f3c48af7b820 Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Mon, 15 Aug 2022 17:58:20 +0500 Subject: [PATCH 05/34] chore: #60: adds base version of refresh in the core package --- .../ApplicationBuilderExtension.cs | 16 ++++ .../AuthenticationExtensions.cs | 14 ++++ .../Refresh/IRefreshMiddlewareBuilder.cs | 17 +++++ .../Refresh/Models/RefreshModel.cs | 7 ++ .../Middlewares/Refresh/RefreshMiddleware.cs | 68 +++++++++++++++++ .../Refresh/RefreshMiddlewareBuilder.cs | 73 +++++++++++++++++++ .../Request/CoreRefreshTokenRequestModel.cs | 9 +++ .../Options/RefreshEndpointOptions.cs | 13 ++++ .../Options/RefreshTokenOptions.cs | 13 ++++ .../Services/ICoreRefreshService.cs | 16 ++-- .../Services/Implementation/LoginService.cs | 26 +++---- .../Implementation/LoginWithRefreshService.cs | 31 ++++++++ 12 files changed, 281 insertions(+), 22 deletions(-) create mode 100644 JwtAuthentication.Core/Middlewares/Refresh/IRefreshMiddlewareBuilder.cs create mode 100644 JwtAuthentication.Core/Middlewares/Refresh/Models/RefreshModel.cs create mode 100644 JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs create mode 100644 JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddlewareBuilder.cs create mode 100644 JwtAuthentication.Core/Models/Request/CoreRefreshTokenRequestModel.cs create mode 100644 JwtAuthentication.Core/Options/RefreshEndpointOptions.cs create mode 100644 JwtAuthentication.Core/Options/RefreshTokenOptions.cs create mode 100644 JwtAuthentication.Core/Services/Implementation/LoginWithRefreshService.cs diff --git a/JwtAuthentication.Core/ApplicationBuilderExtension.cs b/JwtAuthentication.Core/ApplicationBuilderExtension.cs index 59276a5..9f651ef 100644 --- a/JwtAuthentication.Core/ApplicationBuilderExtension.cs +++ b/JwtAuthentication.Core/ApplicationBuilderExtension.cs @@ -4,6 +4,8 @@ using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core @@ -75,6 +77,20 @@ public static IDefaultLoginMiddlewareBuilder OnLoginExecuted(this IApplicationBu .GetInstance() .SetAppBuilder(applicationBuilder) .OnLoginExecuted(callback); + } + + /// + /// Adds middleware to handle incoming login and token refresh requests. + /// + /// + /// + /// + public static IApplicationBuilder UseRefreshTokenMiddleware(this IApplicationBuilder applicationBuilder, RefreshEndpointOptions endpointOptions = null) + { + Func defaultOnRefreshCallback = s => Task.CompletedTask; + + return applicationBuilder + .UseMiddleware(endpointOptions ?? new RefreshEndpointOptions(), defaultOnRefreshCallback, defaultOnRefreshCallback); } } } \ No newline at end of file diff --git a/JwtAuthentication.Core/AuthenticationExtensions.cs b/JwtAuthentication.Core/AuthenticationExtensions.cs index 8b5fce2..03dda4c 100644 --- a/JwtAuthentication.Core/AuthenticationExtensions.cs +++ b/JwtAuthentication.Core/AuthenticationExtensions.cs @@ -8,6 +8,7 @@ using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract.Implementation; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Filters; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Signing; @@ -80,6 +81,19 @@ public static IServiceCollection WithUserClaimsProvider( RequiresPermission.ClaimType = permissionClaimTypeKey; return services.AddTransient(typeof(IUserClaimsProvider), typeof(TUserClaimsProvider)); + } + + public static IServiceCollection AddLoginWithRefresh( + this IServiceCollection services, + RefreshTokenOptions refreshTokenOptions = null) + { + services.AddSingleton(refreshTokenOptions ?? new RefreshTokenOptions()); + + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + return services; } internal static void AddJwtBearer( diff --git a/JwtAuthentication.Core/Middlewares/Refresh/IRefreshMiddlewareBuilder.cs b/JwtAuthentication.Core/Middlewares/Refresh/IRefreshMiddlewareBuilder.cs new file mode 100644 index 0000000..f47cdd1 --- /dev/null +++ b/JwtAuthentication.Core/Middlewares/Refresh/IRefreshMiddlewareBuilder.cs @@ -0,0 +1,17 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh +{ + public interface IRefreshMiddlewareBuilder + { + public IRefreshMiddlewareBuilder OnRefreshExecuting(Func callback); + + public IRefreshMiddlewareBuilder OnRefreshExecuted(Func callback); + + public IApplicationBuilder UseRefreshMiddleware(RefreshEndpointOptions refreshEndpointOptions = null); + } +} \ No newline at end of file diff --git a/JwtAuthentication.Core/Middlewares/Refresh/Models/RefreshModel.cs b/JwtAuthentication.Core/Middlewares/Refresh/Models/RefreshModel.cs new file mode 100644 index 0000000..3c8ee57 --- /dev/null +++ b/JwtAuthentication.Core/Middlewares/Refresh/Models/RefreshModel.cs @@ -0,0 +1,7 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models +{ + public class RefreshModel + { + public string RefreshTokenValue { get; set; } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs b/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs new file mode 100644 index 0000000..a01ab88 --- /dev/null +++ b/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs @@ -0,0 +1,68 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh +{ + internal class RefreshMiddleware : RequestMiddlewareBase + { + private readonly RefreshEndpointOptions _endpointOptions; + private readonly ILogger _logger; + + private readonly Func _onRefreshExecuting; + private readonly Func _onRefreshExecuted; + + public RefreshMiddleware( + RequestDelegate next, + RefreshEndpointOptions endpointOptions, + ILogger logger, + Func onRefreshExecuting, + Func onRefreshExecuted) + : base(next) + { + _endpointOptions = endpointOptions; + _logger = logger; + _onRefreshExecuting = onRefreshExecuting; + _onRefreshExecuted = onRefreshExecuted; + } + + public async Task InvokeAsync(HttpContext context, ICoreRefreshService refreshService) + { + await InvokeAsyncBase(context, refreshService, _endpointOptions.RefreshEndpointRoute); + } + + protected override async Task ExecuteServiceMethod( + CoreRefreshTokenRequestModel requestModel, + ICoreRefreshService service, + HttpContext context) + { + var result = new TokenModel(); + + try + { + var contractRefreshModel = new RefreshModel + { + RefreshTokenValue = requestModel.RefreshTokenValue, + }; + + await _onRefreshExecuting(contractRefreshModel); + result = await service.RefreshAsync(contractRefreshModel.RefreshTokenValue); + await _onRefreshExecuted(contractRefreshModel); + } + catch (AuthenticationException ex) + { + context.Response.StatusCode = StatusCodes.Status409Conflict; + _logger.LogError(ex.ToString()); + } + + return result; + } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddlewareBuilder.cs b/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddlewareBuilder.cs new file mode 100644 index 0000000..3826b79 --- /dev/null +++ b/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddlewareBuilder.cs @@ -0,0 +1,73 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh +{ + public class RefreshMiddlewareBuilder : IRefreshMiddlewareBuilder + { + private static Func _onRefreshExecutingCallback = s => Task.CompletedTask; + private static Func _onRefreshExecutedCallback = s => Task.CompletedTask; + + private IApplicationBuilder _applicationBuilder; + + private static RefreshMiddlewareBuilder _instance; + + private RefreshMiddlewareBuilder() + { + } + + internal static RefreshMiddlewareBuilder GetInstance() + { + if (_instance != null) + { + return _instance; + } + + _instance = new RefreshMiddlewareBuilder(); + + return _instance; + } + + internal IRefreshMiddlewareBuilder SetAppBuilder(IApplicationBuilder applicationBuilder) + { + _applicationBuilder = applicationBuilder; + return this; + } + + /// + /// Registering a callback function to perform actions when when the refresh starts. + /// + /// + /// + public IRefreshMiddlewareBuilder OnRefreshExecuting(Func callback) + { + _onRefreshExecutingCallback = callback; + return this; + } + + /// + /// Registering a callback function to perform actions when the refresh ends. + /// + /// + /// + public IRefreshMiddlewareBuilder OnRefreshExecuted(Func callback) + { + _onRefreshExecutedCallback = callback; + return this; + } + + /// + /// Adds middleware to handle incoming logout requests. + /// + /// + /// + public IApplicationBuilder UseRefreshMiddleware(RefreshEndpointOptions refreshEndpointOptions = null) + { + return _applicationBuilder + .UseMiddleware(refreshEndpointOptions ?? new RefreshEndpointOptions(), _onRefreshExecutingCallback, _onRefreshExecutedCallback); + } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Core/Models/Request/CoreRefreshTokenRequestModel.cs b/JwtAuthentication.Core/Models/Request/CoreRefreshTokenRequestModel.cs new file mode 100644 index 0000000..642c725 --- /dev/null +++ b/JwtAuthentication.Core/Models/Request/CoreRefreshTokenRequestModel.cs @@ -0,0 +1,9 @@ +using System; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request +{ + public class CoreRefreshTokenRequestModel + { + public string RefreshTokenValue { get; set; } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Core/Options/RefreshEndpointOptions.cs b/JwtAuthentication.Core/Options/RefreshEndpointOptions.cs new file mode 100644 index 0000000..d5aa1c3 --- /dev/null +++ b/JwtAuthentication.Core/Options/RefreshEndpointOptions.cs @@ -0,0 +1,13 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Options +{ + public class RefreshEndpointOptions + { + private string _refreshEndpointRoute; + + public string RefreshEndpointRoute + { + get => _refreshEndpointRoute ?? "/auth/refresh"; + set => _refreshEndpointRoute = value; + } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Core/Options/RefreshTokenOptions.cs b/JwtAuthentication.Core/Options/RefreshTokenOptions.cs new file mode 100644 index 0000000..609bd97 --- /dev/null +++ b/JwtAuthentication.Core/Options/RefreshTokenOptions.cs @@ -0,0 +1,13 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Options +{ + public class RefreshTokenOptions + { + private int _refreshTokenExpireInMinutes; + + public int RefreshTokenExpireInMinutes + { + get => _refreshTokenExpireInMinutes == default ? 10080 : _refreshTokenExpireInMinutes; + set => _refreshTokenExpireInMinutes = value; + } + } +} diff --git a/JwtAuthentication.Core/Services/ICoreRefreshService.cs b/JwtAuthentication.Core/Services/ICoreRefreshService.cs index d31306a..9346ffe 100644 --- a/JwtAuthentication.Core/Services/ICoreRefreshService.cs +++ b/JwtAuthentication.Core/Services/ICoreRefreshService.cs @@ -1,10 +1,10 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services -{ - internal interface ICoreRefreshService - { - public Task RefreshAsync(string jwtRefreshToken); - } + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services +{ + internal interface ICoreRefreshService + { + public Task RefreshAsync(string jwtRefreshToken); + } } \ No newline at end of file diff --git a/JwtAuthentication.Core/Services/Implementation/LoginService.cs b/JwtAuthentication.Core/Services/Implementation/LoginService.cs index 8cc9e35..375b6eb 100644 --- a/JwtAuthentication.Core/Services/Implementation/LoginService.cs +++ b/JwtAuthentication.Core/Services/Implementation/LoginService.cs @@ -1,7 +1,6 @@ using System.Threading.Tasks; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; @@ -22,25 +21,24 @@ public LoginService( _userCredentialsValidator = userCredentialsValidator; } - public async Task LoginAsync(LoginRequestModel model) + public virtual async Task LoginAsync(LoginRequestModel model) { + await ValidateCredentials(model); + + return new AuthResponseModel + { + AccessToken = await _tokenManager.GenerateAccessTokenAsync(model.Login) + }; + } + + protected virtual async Task ValidateCredentials(LoginRequestModel model) + { var isUserCredentialsValid = await _userCredentialsValidator.ValidateUserCredentials(model.Login, model.Password); if (!isUserCredentialsValid) { throw new AuthenticationException(ErrorTypes.IncorrectLoginOrPassword); - } - - var token = await _tokenManager.GenerateAccessTokenAsync(model.Login); - - return new AuthResponseModel - { - AccessToken = new TokenModel - { - Value = token.Value, - ExpiresInUtc = token.ExpiresInUtc, - }, - }; + } } } } \ No newline at end of file diff --git a/JwtAuthentication.Core/Services/Implementation/LoginWithRefreshService.cs b/JwtAuthentication.Core/Services/Implementation/LoginWithRefreshService.cs new file mode 100644 index 0000000..22e0e7d --- /dev/null +++ b/JwtAuthentication.Core/Services/Implementation/LoginWithRefreshService.cs @@ -0,0 +1,31 @@ +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation +{ + internal class LoginWithRefreshService : LoginService + { + private readonly ITokenManager _tokenManager; + + public LoginWithRefreshService( + ITokenManager tokenManager, + IUserCredentialsValidator userCredentialsValidator = null) + : base(tokenManager, userCredentialsValidator) + { + _tokenManager = tokenManager; + } + + public override async Task LoginAsync(LoginRequestModel model) + { + await base.ValidateCredentials(model); + + return new AuthResponseModel + { + AccessToken = await _tokenManager.GenerateAccessTokenAsync(model.Login), + RefreshToken = await _tokenManager.GenerateAccessTokenAsync(model.Login), + }; + } + } +} From e3013cc419dc670a12ddba5fcc34d7ab30fde55c Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Tue, 16 Aug 2022 09:57:21 +0500 Subject: [PATCH 06/34] chore: #60: temporary comments the refresh feature in the identity package --- .../ApplicationBuilderExtensions.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/JwtAuthentication.Identity/ApplicationBuilderExtensions.cs b/JwtAuthentication.Identity/ApplicationBuilderExtensions.cs index f86b6ff..1b20566 100644 --- a/JwtAuthentication.Identity/ApplicationBuilderExtensions.cs +++ b/JwtAuthentication.Identity/ApplicationBuilderExtensions.cs @@ -92,19 +92,19 @@ public static IApplicationBuilder UseDefaultDbUser( .UseAuthorization(); } - /// - /// Adds middleware to handle incoming login and token refresh requests. - /// - /// - /// - /// - public static IApplicationBuilder UseRefreshTokenMiddleware(this IApplicationBuilder applicationBuilder, RefreshEndpointOptions endpointOptions = null) - { - Func defaultOnRefreshCallback = s => Task.CompletedTask; + ///// + ///// Adds middleware to handle incoming login and token refresh requests. + ///// + ///// + ///// + ///// + //public static IApplicationBuilder UseRefreshTokenMiddleware(this IApplicationBuilder applicationBuilder, RefreshEndpointOptions endpointOptions = null) + //{ + // Func defaultOnRefreshCallback = s => Task.CompletedTask; - return applicationBuilder - .UseMiddleware(endpointOptions ?? new RefreshEndpointOptions(), defaultOnRefreshCallback, defaultOnRefreshCallback); - } + // return applicationBuilder + // .UseMiddleware(endpointOptions ?? new RefreshEndpointOptions(), defaultOnRefreshCallback, defaultOnRefreshCallback); + //} /// /// Adds middleware to handle incoming user registration requests. It requires a function to map model received from client From 99278d5fdedeb894918d3cf6dfbbf7eacf9952e6 Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Tue, 16 Aug 2022 09:57:52 +0500 Subject: [PATCH 07/34] chore: #60: adds jst token creator --- JwtAuthentication.Core/Consts.cs | 7 ++++ .../Contract/IJwtTokenCreator.cs | 19 +++++++++ .../Contract/JwtTokenCreator.cs | 40 +++++++++++++++++++ JwtAuthentication.Core/Contract/TokenType.cs | 13 ++++++ 4 files changed, 79 insertions(+) create mode 100644 JwtAuthentication.Core/Consts.cs create mode 100644 JwtAuthentication.Core/Contract/IJwtTokenCreator.cs create mode 100644 JwtAuthentication.Core/Contract/JwtTokenCreator.cs create mode 100644 JwtAuthentication.Core/Contract/TokenType.cs diff --git a/JwtAuthentication.Core/Consts.cs b/JwtAuthentication.Core/Consts.cs new file mode 100644 index 0000000..8d0d780 --- /dev/null +++ b/JwtAuthentication.Core/Consts.cs @@ -0,0 +1,7 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core +{ + public static class Consts + { + public const string TokenTypeClaimName = "tokenType"; + } +} diff --git a/JwtAuthentication.Core/Contract/IJwtTokenCreator.cs b/JwtAuthentication.Core/Contract/IJwtTokenCreator.cs new file mode 100644 index 0000000..ef6d8f5 --- /dev/null +++ b/JwtAuthentication.Core/Contract/IJwtTokenCreator.cs @@ -0,0 +1,19 @@ +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.Security.Claims; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract +{ + internal interface IJwtTokenCreator + { + string Create( + string issuer, + string audience, + List claims, + DateTime expires, + SigningCredentials credentials, + string tokenType + ); + } +} diff --git a/JwtAuthentication.Core/Contract/JwtTokenCreator.cs b/JwtAuthentication.Core/Contract/JwtTokenCreator.cs new file mode 100644 index 0000000..a145ebb --- /dev/null +++ b/JwtAuthentication.Core/Contract/JwtTokenCreator.cs @@ -0,0 +1,40 @@ +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract +{ + public class JwtTokenCreator : IJwtTokenCreator + { + public string Create(string issuer, string audience, List claims, DateTime expires, SigningCredentials credentials, string tokenType) + { + if (!TokenType.IsTokenType(tokenType)) + { + throw new ArgumentException("Invalid token type value"); + } + + AddTokenTypeClaim(claims, tokenType); + + var token = new JwtSecurityToken(issuer, + audience, + claims, + expires: expires, + signingCredentials: credentials + ); + + return new JwtSecurityTokenHandler().WriteToken(token); + } + + private void AddTokenTypeClaim(List claims, string tokenType) + { + var isTokenTypeClaimSet = claims.Exists(x => x.Type == Consts.TokenTypeClaimName); + + if (!isTokenTypeClaimSet) + { + claims.Add(new Claim(Consts.TokenTypeClaimName, tokenType)); + } + } + } +} diff --git a/JwtAuthentication.Core/Contract/TokenType.cs b/JwtAuthentication.Core/Contract/TokenType.cs new file mode 100644 index 0000000..1800daa --- /dev/null +++ b/JwtAuthentication.Core/Contract/TokenType.cs @@ -0,0 +1,13 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract +{ + public static class TokenType + { + public const string Refresh = "refresh"; + public const string Access = "access"; + + public static bool IsTokenType(string value) + { + return value == Refresh || value == Access; + } + } +} From 54822b369b86c16ac7eca07ba5aa5434e753dbcb Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Tue, 16 Aug 2022 11:26:53 +0500 Subject: [PATCH 08/34] chore: #60: removes unnecessary code --- .../Signing/SigningHelper.cs | 29 ------------------- 1 file changed, 29 deletions(-) delete mode 100644 JwtAuthentication.Identity/Signing/SigningHelper.cs diff --git a/JwtAuthentication.Identity/Signing/SigningHelper.cs b/JwtAuthentication.Identity/Signing/SigningHelper.cs deleted file mode 100644 index 0843440..0000000 --- a/JwtAuthentication.Identity/Signing/SigningHelper.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Security.Cryptography; -using Microsoft.IdentityModel.Tokens; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Signing -{ - public static class SigningHelper - { - public static RsaSecurityKey GetPublicKey(string key) - { - var publicKey = Convert.FromBase64String(key); - - var rsa = RSA.Create(); - rsa.ImportSubjectPublicKeyInfo(publicKey, out _); - - return new RsaSecurityKey(rsa); - } - - public static RsaSecurityKey GetPrivateKey(string key) - { - var privateKey = Convert.FromBase64String(key); - - var rsa = RSA.Create(); - rsa.ImportRSAPrivateKey(privateKey, out _); - - return new RsaSecurityKey(rsa); - } - } -} \ No newline at end of file From 1c4490047f4722ce8e21bc9e22cec75c19e0fd30 Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Tue, 16 Aug 2022 13:13:15 +0500 Subject: [PATCH 09/34] test(units): #60: adds the jwt token creator tests --- Examples/Tests/Tests.csproj | 4 - .../Tests/Units/JwtTokenGeneratorTests.cs | 105 ++++++++++++++++++ ...tTokenCreator.cs => IJwtTokenGenerator.cs} | 4 +- ...wtTokenCreator.cs => JwtTokenGenerator.cs} | 4 +- 4 files changed, 109 insertions(+), 8 deletions(-) create mode 100644 Examples/Tests/Units/JwtTokenGeneratorTests.cs rename JwtAuthentication.Core/Contract/{IJwtTokenCreator.cs => IJwtTokenGenerator.cs} (82%) rename JwtAuthentication.Core/Contract/{JwtTokenCreator.cs => JwtTokenGenerator.cs} (81%) diff --git a/Examples/Tests/Tests.csproj b/Examples/Tests/Tests.csproj index 7a49897..20a18c5 100644 --- a/Examples/Tests/Tests.csproj +++ b/Examples/Tests/Tests.csproj @@ -36,10 +36,6 @@ - - - - PreserveNewest diff --git a/Examples/Tests/Units/JwtTokenGeneratorTests.cs b/Examples/Tests/Units/JwtTokenGeneratorTests.cs new file mode 100644 index 0000000..ecab5db --- /dev/null +++ b/Examples/Tests/Units/JwtTokenGeneratorTests.cs @@ -0,0 +1,105 @@ +using Microsoft.IdentityModel.Tokens; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using TourmalineCore.AspNetCore.JwtAuthentication.Core; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Signing; +using Xunit; + +namespace Tests.Units; + +public class JwtTokenGeneratorTests +{ + private readonly IJwtTokenGenerator _jwtTokenGenerator; + + private const string Issuer = null; + private const string Audience = null; + private SigningCredentials SigningCredentials = null; + private DateTime Expires = new DateTime(2042, 12, 31); + private List EmptyClaims = new List(); + + private const string PrivateSigningKey = "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU"; + + public JwtTokenGeneratorTests() + { + _jwtTokenGenerator = new JwtTokenGenerator(); + + var privateKey = SigningHelper.GetPrivateKey(PrivateSigningKey); + SigningCredentials = new SigningCredentials(privateKey, SecurityAlgorithms.RsaSha256); + } + + [Fact] + public void GenerateJwtToken_TokenTypeIsInvalid_CatchException() + { + var exception = Record.Exception(() => _jwtTokenGenerator.Generate(Issuer, Audience, EmptyClaims, Expires, SigningCredentials, "invalidTokenValue")); + Assert.NotNull(exception); + } + + [Fact] + public void GenerateAccessJwtToken() + { + var expectedAccessToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlblR5cGUiOiJhY2Nlc3MiLCJleHAiOjIzMDM1Nzg4MDB9.X89rNuFFSFpwnwJ1j0bg89XPBfD4qkxk_h76IO3ogThtHWT2S5bnfUmQM-as1zevC4CSljIUWl4TNzg-R9YNPqkZVs7yeztP4V9nj2SCRH5LllPbL0ULsuxxkGKpbpPN7bNEXTiykbwE7Ea42aYR1qjrZABvWn2WBI3dsVfzRqXEvsUMKq-8pxl8K45JLdV87bkO3uy1PWhadb9E_qPM2f6Y1xRXPR5y685pDmRZYJAqSbId_uKN52CzE2eiwQXxD3jyXadMLsIwS489XQ01k3HGWvpH-0ilUr_hhyPGNGL9_NJc5SqkDADqxh9doLqyHo3cPM4MZ6FilI4qpCciJg"; + var accessToken = _jwtTokenGenerator.Generate(Issuer, Audience, EmptyClaims, Expires, SigningCredentials, TokenType.Access); + + Assert.Equal(expectedAccessToken, accessToken); + Assert.Equal(TokenType.Access, GetTokenTypeClaim(accessToken).Value); + } + + [Fact] + public void GenerateRefreshJwtToken() + { + var expectedAccessToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlblR5cGUiOiJyZWZyZXNoIiwiZXhwIjoyMzAzNTc4ODAwfQ.goyF9EVfnq0np_r473GICCfJDKy8-7QGe1UV4Ara2qolKMRa7mXAgyoI6d1RQhO7NhnfSbsO0dlISsoNgZ0Xh72K253DOf6MFuri84uPSf1-Q5zqBz4z97s1RjpEWcPt-eirXs0uhaZ1Uyf0rYccUBst6ORnfUHRXyqTtujenKybFCokY4bRmCnjIvfdK-QVZlmF3npKZzcb0A6lrPfyaBS45G2iN8Gw5AjCikPfKyKguBFNIb8JpFaOgCKBaE-d6HrSrJGKkBiE3m0jhTelEN9qADwDefAA15iBTLBK_CbNbzyWuL47fuvguWotozBU2OyD-9lqSo4Fpxw9VyhTOw"; + var accessToken = _jwtTokenGenerator.Generate(Issuer, Audience, EmptyClaims, Expires, SigningCredentials, TokenType.Refresh); + + Assert.Equal(expectedAccessToken, accessToken); + Assert.Equal(TokenType.Refresh, GetTokenTypeClaim(accessToken).Value); + } + + [Fact] + public void GenerateAccessJwtToken_TokenTypeClaimAlreadyAdded() + { + var expectedAccessToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlblR5cGUiOiJhY2Nlc3MiLCJleHAiOjIzMDM1Nzg4MDB9.X89rNuFFSFpwnwJ1j0bg89XPBfD4qkxk_h76IO3ogThtHWT2S5bnfUmQM-as1zevC4CSljIUWl4TNzg-R9YNPqkZVs7yeztP4V9nj2SCRH5LllPbL0ULsuxxkGKpbpPN7bNEXTiykbwE7Ea42aYR1qjrZABvWn2WBI3dsVfzRqXEvsUMKq-8pxl8K45JLdV87bkO3uy1PWhadb9E_qPM2f6Y1xRXPR5y685pDmRZYJAqSbId_uKN52CzE2eiwQXxD3jyXadMLsIwS489XQ01k3HGWvpH-0ilUr_hhyPGNGL9_NJc5SqkDADqxh9doLqyHo3cPM4MZ6FilI4qpCciJg"; + + var claims = new List() + { + new Claim(Consts.TokenTypeClaimName, TokenType.Access) + }; + + var accessToken = _jwtTokenGenerator.Generate(Issuer, Audience, claims, Expires, SigningCredentials, TokenType.Access); + + Assert.Equal(expectedAccessToken, accessToken); + Assert.Equal(TokenType.Access, GetTokenTypeClaim(accessToken).Value); + } + + [Fact] + public void GenerateAccessJwtToken_IfThereAreAdditionalClaims() + { + const string additionalClaimType = "ExamplePermission"; + const string additionalClaimValue = "ExampleClaimValue"; + + var claims = new List() + { + new Claim(additionalClaimType, additionalClaimValue), + }; + + var accessToken = _jwtTokenGenerator.Generate(Issuer, Audience, claims, Expires, SigningCredentials, TokenType.Access); + + var exampleClaim = GetClaim(accessToken, additionalClaimType); + var tokenTypeClaim = GetTokenTypeClaim(accessToken); + + Assert.Equal(additionalClaimValue, exampleClaim.Value); + Assert.Equal(TokenType.Access, tokenTypeClaim.Value); + } + + private Claim GetClaim(string tokenValue, string claimType) + { + var token = new JwtSecurityTokenHandler().ReadJwtToken(tokenValue); + + return token.Claims.SingleOrDefault(claim => claim.Type == claimType); + } + + private Claim GetTokenTypeClaim(string tokenValue) + { + return GetClaim(tokenValue, Consts.TokenTypeClaimName); + } +} \ No newline at end of file diff --git a/JwtAuthentication.Core/Contract/IJwtTokenCreator.cs b/JwtAuthentication.Core/Contract/IJwtTokenGenerator.cs similarity index 82% rename from JwtAuthentication.Core/Contract/IJwtTokenCreator.cs rename to JwtAuthentication.Core/Contract/IJwtTokenGenerator.cs index ef6d8f5..7435168 100644 --- a/JwtAuthentication.Core/Contract/IJwtTokenCreator.cs +++ b/JwtAuthentication.Core/Contract/IJwtTokenGenerator.cs @@ -5,9 +5,9 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract { - internal interface IJwtTokenCreator + internal interface IJwtTokenGenerator { - string Create( + string Generate( string issuer, string audience, List claims, diff --git a/JwtAuthentication.Core/Contract/JwtTokenCreator.cs b/JwtAuthentication.Core/Contract/JwtTokenGenerator.cs similarity index 81% rename from JwtAuthentication.Core/Contract/JwtTokenCreator.cs rename to JwtAuthentication.Core/Contract/JwtTokenGenerator.cs index a145ebb..d5e654a 100644 --- a/JwtAuthentication.Core/Contract/JwtTokenCreator.cs +++ b/JwtAuthentication.Core/Contract/JwtTokenGenerator.cs @@ -6,9 +6,9 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract { - public class JwtTokenCreator : IJwtTokenCreator + public class JwtTokenGenerator : IJwtTokenGenerator { - public string Create(string issuer, string audience, List claims, DateTime expires, SigningCredentials credentials, string tokenType) + public string Generate(string issuer, string audience, List claims, DateTime expires, SigningCredentials credentials, string tokenType) { if (!TokenType.IsTokenType(tokenType)) { From e1ac03339cf0a0c80748665fa1757f7feeb0edba Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Tue, 16 Aug 2022 14:27:29 +0500 Subject: [PATCH 10/34] chore: #60: changes the jwt token creator contract --- .../Tests/NetCore5.0/LoginCallbackTests.cs | 18 ++--- .../Tests/NetCore6.0/LoginCallbackTests.cs | 20 +++--- ...eratorTests.cs => JwtTokenCreatorTests.cs} | 68 +++++++++---------- .../AuthenticationExtensions.cs | 3 +- .../Contract/IJwtTokenCreator.cs | 13 ++++ .../Contract/IJwtTokenGenerator.cs | 19 ------ .../Contract/JwtTokenCreator.cs | 64 +++++++++++++++++ .../Contract/JwtTokenGenerator.cs | 40 ----------- JwtAuthentication.Core/Contract/TokenType.cs | 2 +- .../Services/ICoreRefreshTokenManager.cs | 10 +++ .../Services/Implementation/TokenManager.cs | 41 ++++------- 11 files changed, 156 insertions(+), 142 deletions(-) rename Examples/Tests/Units/{JwtTokenGeneratorTests.cs => JwtTokenCreatorTests.cs} (58%) create mode 100644 JwtAuthentication.Core/Contract/IJwtTokenCreator.cs delete mode 100644 JwtAuthentication.Core/Contract/IJwtTokenGenerator.cs create mode 100644 JwtAuthentication.Core/Contract/JwtTokenCreator.cs delete mode 100644 JwtAuthentication.Core/Contract/JwtTokenGenerator.cs create mode 100644 JwtAuthentication.Core/Services/ICoreRefreshTokenManager.cs diff --git a/Examples/Tests/NetCore5.0/LoginCallbackTests.cs b/Examples/Tests/NetCore5.0/LoginCallbackTests.cs index c2c9d06..d0b22e8 100644 --- a/Examples/Tests/NetCore5.0/LoginCallbackTests.cs +++ b/Examples/Tests/NetCore5.0/LoginCallbackTests.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Http; using Moq; using Newtonsoft.Json; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract.Implementation; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models; @@ -45,15 +46,14 @@ public LoginCallbackTests() _onLoginExecutedMock.Setup(p => p(It.IsAny())) .Returns(Task.CompletedTask); - _loginService = new LoginService(new TokenManager(new AuthenticationOptions - { - PrivateSigningKey = - "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU", - }, - new DefaultUserClaimsProvider() - ), - new FakeUserCredentialValidator() - ); + var authenticationOptions = new AuthenticationOptions() + { + PrivateSigningKey = "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU", + }; + + _loginService = new LoginService( + new TokenManager(authenticationOptions, new DefaultUserClaimsProvider(), new JwtTokenCreator(authenticationOptions)), + new FakeUserCredentialValidator()); } [Fact] diff --git a/Examples/Tests/NetCore6.0/LoginCallbackTests.cs b/Examples/Tests/NetCore6.0/LoginCallbackTests.cs index 79d1fba..f60752d 100644 --- a/Examples/Tests/NetCore6.0/LoginCallbackTests.cs +++ b/Examples/Tests/NetCore6.0/LoginCallbackTests.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.Http; using Moq; using Newtonsoft.Json; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract.Implementation; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models; @@ -44,16 +45,15 @@ public LoginCallbackTests() _onLoginExecutedMock.Setup(p => p(It.IsAny())) .Returns(Task.CompletedTask); - - _loginService = new LoginService(new TokenManager(new AuthenticationOptions - { - PrivateSigningKey = - "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU", - }, - new DefaultUserClaimsProvider() - ), - new FakeUserCredentialValidator() - ); + + var authenticationOptions = new AuthenticationOptions() + { + PrivateSigningKey = "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU", + }; + + _loginService = new LoginService( + new TokenManager(authenticationOptions, new DefaultUserClaimsProvider(), new JwtTokenCreator(authenticationOptions)), + new FakeUserCredentialValidator()); } [Fact] diff --git a/Examples/Tests/Units/JwtTokenGeneratorTests.cs b/Examples/Tests/Units/JwtTokenCreatorTests.cs similarity index 58% rename from Examples/Tests/Units/JwtTokenGeneratorTests.cs rename to Examples/Tests/Units/JwtTokenCreatorTests.cs index ecab5db..0daede4 100644 --- a/Examples/Tests/Units/JwtTokenGeneratorTests.cs +++ b/Examples/Tests/Units/JwtTokenCreatorTests.cs @@ -1,62 +1,62 @@ -using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using TourmalineCore.AspNetCore.JwtAuthentication.Core; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Signing; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; using Xunit; namespace Tests.Units; -public class JwtTokenGeneratorTests +public class JwtTokenCreatorTests { - private readonly IJwtTokenGenerator _jwtTokenGenerator; + private readonly IJwtTokenCreator _jwtTokenCreator; - private const string Issuer = null; - private const string Audience = null; - private SigningCredentials SigningCredentials = null; - private DateTime Expires = new DateTime(2042, 12, 31); - private List EmptyClaims = new List(); + private DateTime TokenExpiresIn = new DateTime(2042, 12, 31); + private List EmptyClaims = new List(); private const string PrivateSigningKey = "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU"; - public JwtTokenGeneratorTests() + public JwtTokenCreatorTests() { - _jwtTokenGenerator = new JwtTokenGenerator(); + var authenticationOptions = new AuthenticationOptions() + { + PrivateSigningKey = PrivateSigningKey, + }; - var privateKey = SigningHelper.GetPrivateKey(PrivateSigningKey); - SigningCredentials = new SigningCredentials(privateKey, SecurityAlgorithms.RsaSha256); + _jwtTokenCreator = new JwtTokenCreator(authenticationOptions); } [Fact] - public void GenerateJwtToken_TokenTypeIsInvalid_CatchException() + public async Task CreateJwtToken_TokenTypeIsInvalid_CatchException() { - var exception = Record.Exception(() => _jwtTokenGenerator.Generate(Issuer, Audience, EmptyClaims, Expires, SigningCredentials, "invalidTokenValue")); + var exception = await Record.ExceptionAsync(() => _jwtTokenCreator.CreateAsync("invalidTokenType", EmptyClaims, TokenExpiresIn)); Assert.NotNull(exception); + Assert.Equal("Invalid token type value", exception.Message); } [Fact] - public void GenerateAccessJwtToken() + public async Task CreateAccessJwtToken() { var expectedAccessToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlblR5cGUiOiJhY2Nlc3MiLCJleHAiOjIzMDM1Nzg4MDB9.X89rNuFFSFpwnwJ1j0bg89XPBfD4qkxk_h76IO3ogThtHWT2S5bnfUmQM-as1zevC4CSljIUWl4TNzg-R9YNPqkZVs7yeztP4V9nj2SCRH5LllPbL0ULsuxxkGKpbpPN7bNEXTiykbwE7Ea42aYR1qjrZABvWn2WBI3dsVfzRqXEvsUMKq-8pxl8K45JLdV87bkO3uy1PWhadb9E_qPM2f6Y1xRXPR5y685pDmRZYJAqSbId_uKN52CzE2eiwQXxD3jyXadMLsIwS489XQ01k3HGWvpH-0ilUr_hhyPGNGL9_NJc5SqkDADqxh9doLqyHo3cPM4MZ6FilI4qpCciJg"; - var accessToken = _jwtTokenGenerator.Generate(Issuer, Audience, EmptyClaims, Expires, SigningCredentials, TokenType.Access); + var accessTokenModel = await _jwtTokenCreator.CreateAsync(TokenType.Access, EmptyClaims, TokenExpiresIn); - Assert.Equal(expectedAccessToken, accessToken); - Assert.Equal(TokenType.Access, GetTokenTypeClaim(accessToken).Value); + Assert.Equal(expectedAccessToken, accessTokenModel.Value); + Assert.Equal(TokenType.Access, GetTokenTypeClaim(accessTokenModel).Value); } [Fact] - public void GenerateRefreshJwtToken() + public async Task GenerateRefreshJwtToken() { - var expectedAccessToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlblR5cGUiOiJyZWZyZXNoIiwiZXhwIjoyMzAzNTc4ODAwfQ.goyF9EVfnq0np_r473GICCfJDKy8-7QGe1UV4Ara2qolKMRa7mXAgyoI6d1RQhO7NhnfSbsO0dlISsoNgZ0Xh72K253DOf6MFuri84uPSf1-Q5zqBz4z97s1RjpEWcPt-eirXs0uhaZ1Uyf0rYccUBst6ORnfUHRXyqTtujenKybFCokY4bRmCnjIvfdK-QVZlmF3npKZzcb0A6lrPfyaBS45G2iN8Gw5AjCikPfKyKguBFNIb8JpFaOgCKBaE-d6HrSrJGKkBiE3m0jhTelEN9qADwDefAA15iBTLBK_CbNbzyWuL47fuvguWotozBU2OyD-9lqSo4Fpxw9VyhTOw"; - var accessToken = _jwtTokenGenerator.Generate(Issuer, Audience, EmptyClaims, Expires, SigningCredentials, TokenType.Refresh); + var expectedRefreshToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlblR5cGUiOiJyZWZyZXNoIiwiZXhwIjoyMzAzNTc4ODAwfQ.goyF9EVfnq0np_r473GICCfJDKy8-7QGe1UV4Ara2qolKMRa7mXAgyoI6d1RQhO7NhnfSbsO0dlISsoNgZ0Xh72K253DOf6MFuri84uPSf1-Q5zqBz4z97s1RjpEWcPt-eirXs0uhaZ1Uyf0rYccUBst6ORnfUHRXyqTtujenKybFCokY4bRmCnjIvfdK-QVZlmF3npKZzcb0A6lrPfyaBS45G2iN8Gw5AjCikPfKyKguBFNIb8JpFaOgCKBaE-d6HrSrJGKkBiE3m0jhTelEN9qADwDefAA15iBTLBK_CbNbzyWuL47fuvguWotozBU2OyD-9lqSo4Fpxw9VyhTOw"; + var refreshTokenModel = await _jwtTokenCreator.CreateAsync(TokenType.Refresh, EmptyClaims, TokenExpiresIn); - Assert.Equal(expectedAccessToken, accessToken); - Assert.Equal(TokenType.Refresh, GetTokenTypeClaim(accessToken).Value); + Assert.Equal(expectedRefreshToken, refreshTokenModel.Value); + Assert.Equal(TokenType.Refresh, GetTokenTypeClaim(refreshTokenModel).Value); } [Fact] - public void GenerateAccessJwtToken_TokenTypeClaimAlreadyAdded() + public async Task GenerateAccessJwtToken_TokenTypeClaimAlreadyAdded() { var expectedAccessToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlblR5cGUiOiJhY2Nlc3MiLCJleHAiOjIzMDM1Nzg4MDB9.X89rNuFFSFpwnwJ1j0bg89XPBfD4qkxk_h76IO3ogThtHWT2S5bnfUmQM-as1zevC4CSljIUWl4TNzg-R9YNPqkZVs7yeztP4V9nj2SCRH5LllPbL0ULsuxxkGKpbpPN7bNEXTiykbwE7Ea42aYR1qjrZABvWn2WBI3dsVfzRqXEvsUMKq-8pxl8K45JLdV87bkO3uy1PWhadb9E_qPM2f6Y1xRXPR5y685pDmRZYJAqSbId_uKN52CzE2eiwQXxD3jyXadMLsIwS489XQ01k3HGWvpH-0ilUr_hhyPGNGL9_NJc5SqkDADqxh9doLqyHo3cPM4MZ6FilI4qpCciJg"; @@ -65,14 +65,14 @@ public void GenerateAccessJwtToken_TokenTypeClaimAlreadyAdded() new Claim(Consts.TokenTypeClaimName, TokenType.Access) }; - var accessToken = _jwtTokenGenerator.Generate(Issuer, Audience, claims, Expires, SigningCredentials, TokenType.Access); + var accessTokenModel = await _jwtTokenCreator.CreateAsync(TokenType.Access, claims, TokenExpiresIn); - Assert.Equal(expectedAccessToken, accessToken); - Assert.Equal(TokenType.Access, GetTokenTypeClaim(accessToken).Value); + Assert.Equal(expectedAccessToken, accessTokenModel.Value); + Assert.Equal(TokenType.Access, GetTokenTypeClaim(accessTokenModel).Value); } [Fact] - public void GenerateAccessJwtToken_IfThereAreAdditionalClaims() + public async Task GenerateAccessJwtToken_IfThereAreAdditionalClaims() { const string additionalClaimType = "ExamplePermission"; const string additionalClaimValue = "ExampleClaimValue"; @@ -82,10 +82,10 @@ public void GenerateAccessJwtToken_IfThereAreAdditionalClaims() new Claim(additionalClaimType, additionalClaimValue), }; - var accessToken = _jwtTokenGenerator.Generate(Issuer, Audience, claims, Expires, SigningCredentials, TokenType.Access); + var accessTokenModel = await _jwtTokenCreator.CreateAsync(TokenType.Access, claims, TokenExpiresIn); - var exampleClaim = GetClaim(accessToken, additionalClaimType); - var tokenTypeClaim = GetTokenTypeClaim(accessToken); + var exampleClaim = GetClaim(accessTokenModel.Value, additionalClaimType); + var tokenTypeClaim = GetTokenTypeClaim(accessTokenModel); Assert.Equal(additionalClaimValue, exampleClaim.Value); Assert.Equal(TokenType.Access, tokenTypeClaim.Value); @@ -98,8 +98,8 @@ private Claim GetClaim(string tokenValue, string claimType) return token.Claims.SingleOrDefault(claim => claim.Type == claimType); } - private Claim GetTokenTypeClaim(string tokenValue) + private Claim GetTokenTypeClaim(TokenModel tokenModel) { - return GetClaim(tokenValue, Consts.TokenTypeClaimName); + return GetClaim(tokenModel.Value, Consts.TokenTypeClaimName); } } \ No newline at end of file diff --git a/JwtAuthentication.Core/AuthenticationExtensions.cs b/JwtAuthentication.Core/AuthenticationExtensions.cs index 03dda4c..de0d47d 100644 --- a/JwtAuthentication.Core/AuthenticationExtensions.cs +++ b/JwtAuthentication.Core/AuthenticationExtensions.cs @@ -47,7 +47,8 @@ public static IServiceCollection AddJwtAuthentication( services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddTransient(); + services.AddTransient(); + services.AddTransient(); services.AddJwtBearer(authenticationOptions); diff --git a/JwtAuthentication.Core/Contract/IJwtTokenCreator.cs b/JwtAuthentication.Core/Contract/IJwtTokenCreator.cs new file mode 100644 index 0000000..ac2c366 --- /dev/null +++ b/JwtAuthentication.Core/Contract/IJwtTokenCreator.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract +{ + internal interface IJwtTokenCreator + { + Task CreateAsync(string tokenType, List claims, DateTime tokenExpiresIn); + } +} diff --git a/JwtAuthentication.Core/Contract/IJwtTokenGenerator.cs b/JwtAuthentication.Core/Contract/IJwtTokenGenerator.cs deleted file mode 100644 index 7435168..0000000 --- a/JwtAuthentication.Core/Contract/IJwtTokenGenerator.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.IdentityModel.Tokens; -using System; -using System.Collections.Generic; -using System.Security.Claims; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract -{ - internal interface IJwtTokenGenerator - { - string Generate( - string issuer, - string audience, - List claims, - DateTime expires, - SigningCredentials credentials, - string tokenType - ); - } -} diff --git a/JwtAuthentication.Core/Contract/JwtTokenCreator.cs b/JwtAuthentication.Core/Contract/JwtTokenCreator.cs new file mode 100644 index 0000000..66b1a8d --- /dev/null +++ b/JwtAuthentication.Core/Contract/JwtTokenCreator.cs @@ -0,0 +1,64 @@ +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Signing; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract +{ + internal class JwtTokenCreator : IJwtTokenCreator + { + private readonly AuthenticationOptions _authenticationOptions; + + public JwtTokenCreator(AuthenticationOptions authenticationOptions) + { + _authenticationOptions = authenticationOptions; + } + + public async Task CreateAsync(string tokenType, List claims, DateTime tokenExpiresIn) + { + if (!TokenType.IsAvailableTokenType(tokenType)) + { + throw new ArgumentException("Invalid token type value"); + } + + AddTokenTypeClaim(claims, tokenType); + + var token = new JwtSecurityToken( + _authenticationOptions.Issuer, + _authenticationOptions.Audience, + claims, + expires: tokenExpiresIn, + signingCredentials: GetCredentials()); + + var tokenValue = new JwtSecurityTokenHandler().WriteToken(token); + + return await Task.FromResult(new TokenModel + { + Value = tokenValue, + ExpiresInUtc = tokenExpiresIn.ToUniversalTime(), + }); + } + + private SigningCredentials GetCredentials() + { + var privateKey = SigningHelper.GetPrivateKey(_authenticationOptions.PrivateSigningKey); + + return new SigningCredentials(privateKey, SecurityAlgorithms.RsaSha256); + } + + private void AddTokenTypeClaim(List claims, string tokenTypeValue) + { + var isTokenTypeClaimSet = claims.Exists(x => x.Type == Consts.TokenTypeClaimName); + + if (!isTokenTypeClaimSet) + { + claims.Add(new Claim(Consts.TokenTypeClaimName, tokenTypeValue)); + } + } + } +} diff --git a/JwtAuthentication.Core/Contract/JwtTokenGenerator.cs b/JwtAuthentication.Core/Contract/JwtTokenGenerator.cs deleted file mode 100644 index d5e654a..0000000 --- a/JwtAuthentication.Core/Contract/JwtTokenGenerator.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Microsoft.IdentityModel.Tokens; -using System; -using System.Collections.Generic; -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract -{ - public class JwtTokenGenerator : IJwtTokenGenerator - { - public string Generate(string issuer, string audience, List claims, DateTime expires, SigningCredentials credentials, string tokenType) - { - if (!TokenType.IsTokenType(tokenType)) - { - throw new ArgumentException("Invalid token type value"); - } - - AddTokenTypeClaim(claims, tokenType); - - var token = new JwtSecurityToken(issuer, - audience, - claims, - expires: expires, - signingCredentials: credentials - ); - - return new JwtSecurityTokenHandler().WriteToken(token); - } - - private void AddTokenTypeClaim(List claims, string tokenType) - { - var isTokenTypeClaimSet = claims.Exists(x => x.Type == Consts.TokenTypeClaimName); - - if (!isTokenTypeClaimSet) - { - claims.Add(new Claim(Consts.TokenTypeClaimName, tokenType)); - } - } - } -} diff --git a/JwtAuthentication.Core/Contract/TokenType.cs b/JwtAuthentication.Core/Contract/TokenType.cs index 1800daa..6b76b3c 100644 --- a/JwtAuthentication.Core/Contract/TokenType.cs +++ b/JwtAuthentication.Core/Contract/TokenType.cs @@ -5,7 +5,7 @@ public static class TokenType public const string Refresh = "refresh"; public const string Access = "access"; - public static bool IsTokenType(string value) + public static bool IsAvailableTokenType(string value) { return value == Refresh || value == Access; } diff --git a/JwtAuthentication.Core/Services/ICoreRefreshTokenManager.cs b/JwtAuthentication.Core/Services/ICoreRefreshTokenManager.cs new file mode 100644 index 0000000..90fcc4d --- /dev/null +++ b/JwtAuthentication.Core/Services/ICoreRefreshTokenManager.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services +{ + internal interface ICoreRefreshTokenManager + { + Task GenerateRefreshTokenAsync(string login = null); + } +} diff --git a/JwtAuthentication.Core/Services/Implementation/TokenManager.cs b/JwtAuthentication.Core/Services/Implementation/TokenManager.cs index 8f08cc1..0de8e7b 100644 --- a/JwtAuthentication.Core/Services/Implementation/TokenManager.cs +++ b/JwtAuthentication.Core/Services/Implementation/TokenManager.cs @@ -1,14 +1,11 @@ -using System; +using System; using System.Collections.Generic; -using System.IdentityModel.Tokens.Jwt; using System.Runtime.CompilerServices; using System.Security.Claims; using System.Threading.Tasks; -using Microsoft.IdentityModel.Tokens; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Signing; [assembly: InternalsVisibleTo("TourmalineCore.AspNetCore.JwtAuthentication.Identity")] @@ -17,41 +14,29 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementati internal class TokenManager : ITokenManager { private readonly AuthenticationOptions _options; - private readonly IUserClaimsProvider _userClaimsProvider; + private readonly IUserClaimsProvider _userClaimsProvider; + private readonly IJwtTokenCreator _jwtTokenCreator; public TokenManager( AuthenticationOptions options, - IUserClaimsProvider userClaimsProvider) + IUserClaimsProvider userClaimsProvider, + IJwtTokenCreator jwtTokenCreator) { _options = options; - _userClaimsProvider = userClaimsProvider; + _userClaimsProvider = userClaimsProvider; + _jwtTokenCreator = jwtTokenCreator; } public async Task GenerateAccessTokenAsync(string login = null) - { + { var claims = login == null ? new List() : await _userClaimsProvider.GetUserClaimsAsync(login); - - var privateKey = SigningHelper.GetPrivateKey(_options.PrivateSigningKey); - var credentials = new SigningCredentials(privateKey, SecurityAlgorithms.RsaSha256); - var expires = DateTime.UtcNow.AddMinutes(_options.AccessTokenExpireInMinutes); - - var token = new JwtSecurityToken(_options.Issuer, - _options.Audience, - claims, - expires: expires, - signingCredentials: credentials - ); - - var tokenValue = new JwtSecurityTokenHandler().WriteToken(token); - - return await Task.FromResult(new TokenModel - { - Value = tokenValue, - ExpiresInUtc = expires.ToUniversalTime(), - } - ); + + return await _jwtTokenCreator.CreateAsync( + TokenType.Access, + claims, + DateTime.UtcNow.AddMinutes(_options.AccessTokenExpireInMinutes)); } } } \ No newline at end of file From 2e8dfc74521fe199a23cc3e5c2ec6d81df7e3cbb Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Wed, 17 Aug 2022 10:08:13 +0500 Subject: [PATCH 11/34] chore: #60: adds token type validation in the refresh service --- .../Tests/Units/JwtTokenValidatorTests.cs | 8 ++--- .../Contract/IJwtTokenValidator.cs | 5 +++- .../Contract/JwtTokenValidator.cs | 29 +++++++++++++++++-- .../Services/Implementation/RefreshService.cs | 21 +++++++++----- 4 files changed, 49 insertions(+), 14 deletions(-) diff --git a/Examples/Tests/Units/JwtTokenValidatorTests.cs b/Examples/Tests/Units/JwtTokenValidatorTests.cs index 634cfc4..44cfdd9 100644 --- a/Examples/Tests/Units/JwtTokenValidatorTests.cs +++ b/Examples/Tests/Units/JwtTokenValidatorTests.cs @@ -23,16 +23,16 @@ public JwtTokenValidatorTests() } [Fact] - public void ValidateJwtToken_TokenIsValid_NoExceptions() + public async Task ValidateJwtToken_TokenIsValid_NoExceptions() { - var exception = Record.Exception(() => _jwtTokenValidator.Validate(ValidJwtToken)); + var exception = await Record.ExceptionAsync(() => _jwtTokenValidator.ValidateTokenAsync(ValidJwtToken)); Assert.Null(exception); } [Fact] - public void ValidateJwtToken_TokenIsInvalid_CatchExceptions() + public async Task ValidateJwtToken_TokenIsInvalid_CatchExceptions() { - var exception = Record.Exception(() => _jwtTokenValidator.Validate(InvalidJwtToken)); + var exception = await Record.ExceptionAsync(() => _jwtTokenValidator.ValidateTokenAsync(InvalidJwtToken)); Assert.NotNull(exception); } } \ No newline at end of file diff --git a/JwtAuthentication.Core/Contract/IJwtTokenValidator.cs b/JwtAuthentication.Core/Contract/IJwtTokenValidator.cs index 667cf65..7183e55 100644 --- a/JwtAuthentication.Core/Contract/IJwtTokenValidator.cs +++ b/JwtAuthentication.Core/Contract/IJwtTokenValidator.cs @@ -1,7 +1,10 @@ +using System.Threading.Tasks; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract { internal interface IJwtTokenValidator { - void Validate(string jwtToken); + Task ValidateTokenAsync(string tokenValue); + Task ValidateTokenTypeAsync(string tokenValue, string tokenType); } } diff --git a/JwtAuthentication.Core/Contract/JwtTokenValidator.cs b/JwtAuthentication.Core/Contract/JwtTokenValidator.cs index de4ef15..9c956da 100644 --- a/JwtAuthentication.Core/Contract/JwtTokenValidator.cs +++ b/JwtAuthentication.Core/Contract/JwtTokenValidator.cs @@ -1,6 +1,8 @@ using Microsoft.IdentityModel.Tokens; using System; using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Threading.Tasks; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Signing; @@ -15,7 +17,7 @@ public JwtTokenValidator(AuthenticationOptions options) _authenticationOptions = options; } - public void Validate(string jwtTokenValue) + public Task ValidateTokenAsync(string tokenValue) { var handler = new JwtSecurityTokenHandler(); var tokenValidationParameters = new TokenValidationParameters @@ -28,7 +30,30 @@ public void Validate(string jwtTokenValue) ClockSkew = TimeSpan.Zero, }; - handler.ValidateToken(jwtTokenValue, tokenValidationParameters, out var _); + return Task.Run(() => handler.ValidateToken(tokenValue, tokenValidationParameters, out var _)); + } + + public Task ValidateTokenTypeAsync(string tokenValue, string tokenType) + { + if (!TokenType.IsAvailableTokenType(tokenType)) + { + throw new ArgumentException("Invalid token type value"); + } + + var token = new JwtSecurityTokenHandler().ReadJwtToken(tokenValue); + var tokenTypeClaim = token.Claims.SingleOrDefault(claim => claim.Type == Consts.TokenTypeClaimName); + + if (tokenTypeClaim == null) + { + throw new Exception("Token type claim is not set"); + } + + if (tokenTypeClaim.Value != tokenType) + { + throw new ArgumentException($"Token type is not '{tokenType}'"); + } + + return Task.CompletedTask; } } } diff --git a/JwtAuthentication.Core/Services/Implementation/RefreshService.cs b/JwtAuthentication.Core/Services/Implementation/RefreshService.cs index a5ac5f1..08de518 100644 --- a/JwtAuthentication.Core/Services/Implementation/RefreshService.cs +++ b/JwtAuthentication.Core/Services/Implementation/RefreshService.cs @@ -1,31 +1,38 @@ using System; +using System.Collections.Generic; +using System.Security.Claims; using System.Threading.Tasks; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation { internal class RefreshService : ICoreRefreshService { - private readonly ITokenManager _tokenManager; private readonly IJwtTokenValidator _jwtTokenValidator; + private readonly IJwtTokenCreator _jwtTokenCreator; + private readonly RefreshTokenOptions _refreshTokenOptions; public RefreshService( - ITokenManager tokenManager, - IJwtTokenValidator jwtTokenValidator) + IJwtTokenValidator jwtTokenValidator, + IJwtTokenCreator jwtTokenCreator, + RefreshTokenOptions refreshTokenOptions) { - _tokenManager = tokenManager; _jwtTokenValidator = jwtTokenValidator; + _jwtTokenCreator = jwtTokenCreator; + _refreshTokenOptions = refreshTokenOptions; } - public async Task RefreshAsync(string jwtRefreshToken) + public async Task RefreshAsync(string tokenValue) { try { - _jwtTokenValidator.Validate(jwtRefreshToken); + await _jwtTokenValidator.ValidateTokenAsync(tokenValue); + await _jwtTokenValidator.ValidateTokenTypeAsync(tokenValue, TokenType.Refresh); - return await _tokenManager.GenerateAccessTokenAsync(); + return await _jwtTokenCreator.CreateAsync(TokenType.Refresh, new List(), DateTime.UtcNow.AddMinutes(_refreshTokenOptions.RefreshTokenExpireInMinutes)); } catch (Exception) { From 0725a72d24a458b7a46ba6f357991a9f10e5f329 Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Wed, 17 Aug 2022 10:39:51 +0500 Subject: [PATCH 12/34] chore: #60: changes the contract of the jwt token creator --- Examples/Tests/Units/JwtTokenCreatorTests.cs | 44 +++++++++---------- .../Contract/IJwtTokenCreator.cs | 3 +- .../Contract/JwtTokenCreator.cs | 18 ++++++-- .../Services/Implementation/RefreshService.cs | 6 +-- .../Services/Implementation/TokenManager.cs | 5 +-- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Examples/Tests/Units/JwtTokenCreatorTests.cs b/Examples/Tests/Units/JwtTokenCreatorTests.cs index 0daede4..3c63ba6 100644 --- a/Examples/Tests/Units/JwtTokenCreatorTests.cs +++ b/Examples/Tests/Units/JwtTokenCreatorTests.cs @@ -11,17 +11,13 @@ namespace Tests.Units; public class JwtTokenCreatorTests { private readonly IJwtTokenCreator _jwtTokenCreator; - - private DateTime TokenExpiresIn = new DateTime(2042, 12, 31); - private List EmptyClaims = new List(); - - private const string PrivateSigningKey = "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU"; + private const int TokenLifetimeInMinutes = 15; public JwtTokenCreatorTests() { var authenticationOptions = new AuthenticationOptions() { - PrivateSigningKey = PrivateSigningKey, + PrivateSigningKey = "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU", }; _jwtTokenCreator = new JwtTokenCreator(authenticationOptions); @@ -30,49 +26,49 @@ public JwtTokenCreatorTests() [Fact] public async Task CreateJwtToken_TokenTypeIsInvalid_CatchException() { - var exception = await Record.ExceptionAsync(() => _jwtTokenCreator.CreateAsync("invalidTokenType", EmptyClaims, TokenExpiresIn)); + var exception = await Record.ExceptionAsync(() => _jwtTokenCreator.CreateAsync("invalidTokenType", TokenLifetimeInMinutes)); Assert.NotNull(exception); Assert.Equal("Invalid token type value", exception.Message); } + [Theory] + [InlineData(-1)] + [InlineData(0)] + public async Task CreateJwtToken_TokenLifetimeIsInvalid_CatchException(int tokenLifetimeInMinutes) + { + var exception = await Record.ExceptionAsync(() => _jwtTokenCreator.CreateAsync(TokenType.Access, tokenLifetimeInMinutes)); + Assert.NotNull(exception); + Assert.Equal("Token lifetime cannot be negative or zero", exception.Message); + } + [Fact] public async Task CreateAccessJwtToken() { - var expectedAccessToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlblR5cGUiOiJhY2Nlc3MiLCJleHAiOjIzMDM1Nzg4MDB9.X89rNuFFSFpwnwJ1j0bg89XPBfD4qkxk_h76IO3ogThtHWT2S5bnfUmQM-as1zevC4CSljIUWl4TNzg-R9YNPqkZVs7yeztP4V9nj2SCRH5LllPbL0ULsuxxkGKpbpPN7bNEXTiykbwE7Ea42aYR1qjrZABvWn2WBI3dsVfzRqXEvsUMKq-8pxl8K45JLdV87bkO3uy1PWhadb9E_qPM2f6Y1xRXPR5y685pDmRZYJAqSbId_uKN52CzE2eiwQXxD3jyXadMLsIwS489XQ01k3HGWvpH-0ilUr_hhyPGNGL9_NJc5SqkDADqxh9doLqyHo3cPM4MZ6FilI4qpCciJg"; - var accessTokenModel = await _jwtTokenCreator.CreateAsync(TokenType.Access, EmptyClaims, TokenExpiresIn); - - Assert.Equal(expectedAccessToken, accessTokenModel.Value); + var accessTokenModel = await _jwtTokenCreator.CreateAsync(TokenType.Access, TokenLifetimeInMinutes); Assert.Equal(TokenType.Access, GetTokenTypeClaim(accessTokenModel).Value); } [Fact] - public async Task GenerateRefreshJwtToken() + public async Task CreateRefreshJwtToken() { - var expectedRefreshToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlblR5cGUiOiJyZWZyZXNoIiwiZXhwIjoyMzAzNTc4ODAwfQ.goyF9EVfnq0np_r473GICCfJDKy8-7QGe1UV4Ara2qolKMRa7mXAgyoI6d1RQhO7NhnfSbsO0dlISsoNgZ0Xh72K253DOf6MFuri84uPSf1-Q5zqBz4z97s1RjpEWcPt-eirXs0uhaZ1Uyf0rYccUBst6ORnfUHRXyqTtujenKybFCokY4bRmCnjIvfdK-QVZlmF3npKZzcb0A6lrPfyaBS45G2iN8Gw5AjCikPfKyKguBFNIb8JpFaOgCKBaE-d6HrSrJGKkBiE3m0jhTelEN9qADwDefAA15iBTLBK_CbNbzyWuL47fuvguWotozBU2OyD-9lqSo4Fpxw9VyhTOw"; - var refreshTokenModel = await _jwtTokenCreator.CreateAsync(TokenType.Refresh, EmptyClaims, TokenExpiresIn); - - Assert.Equal(expectedRefreshToken, refreshTokenModel.Value); + var refreshTokenModel = await _jwtTokenCreator.CreateAsync(TokenType.Refresh, TokenLifetimeInMinutes); Assert.Equal(TokenType.Refresh, GetTokenTypeClaim(refreshTokenModel).Value); } [Fact] - public async Task GenerateAccessJwtToken_TokenTypeClaimAlreadyAdded() + public async Task CreateAccessJwtToken_TokenTypeClaimAlreadyAdded() { - var expectedAccessToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlblR5cGUiOiJhY2Nlc3MiLCJleHAiOjIzMDM1Nzg4MDB9.X89rNuFFSFpwnwJ1j0bg89XPBfD4qkxk_h76IO3ogThtHWT2S5bnfUmQM-as1zevC4CSljIUWl4TNzg-R9YNPqkZVs7yeztP4V9nj2SCRH5LllPbL0ULsuxxkGKpbpPN7bNEXTiykbwE7Ea42aYR1qjrZABvWn2WBI3dsVfzRqXEvsUMKq-8pxl8K45JLdV87bkO3uy1PWhadb9E_qPM2f6Y1xRXPR5y685pDmRZYJAqSbId_uKN52CzE2eiwQXxD3jyXadMLsIwS489XQ01k3HGWvpH-0ilUr_hhyPGNGL9_NJc5SqkDADqxh9doLqyHo3cPM4MZ6FilI4qpCciJg"; - var claims = new List() { new Claim(Consts.TokenTypeClaimName, TokenType.Access) }; - var accessTokenModel = await _jwtTokenCreator.CreateAsync(TokenType.Access, claims, TokenExpiresIn); - - Assert.Equal(expectedAccessToken, accessTokenModel.Value); + var accessTokenModel = await _jwtTokenCreator.CreateAsync(TokenType.Access, TokenLifetimeInMinutes, claims); Assert.Equal(TokenType.Access, GetTokenTypeClaim(accessTokenModel).Value); } [Fact] - public async Task GenerateAccessJwtToken_IfThereAreAdditionalClaims() + public async Task CreateAccessJwtToken_IfThereAreAdditionalClaims() { const string additionalClaimType = "ExamplePermission"; const string additionalClaimValue = "ExampleClaimValue"; @@ -82,7 +78,7 @@ public async Task GenerateAccessJwtToken_IfThereAreAdditionalClaims() new Claim(additionalClaimType, additionalClaimValue), }; - var accessTokenModel = await _jwtTokenCreator.CreateAsync(TokenType.Access, claims, TokenExpiresIn); + var accessTokenModel = await _jwtTokenCreator.CreateAsync(TokenType.Access, TokenLifetimeInMinutes, claims); var exampleClaim = GetClaim(accessTokenModel.Value, additionalClaimType); var tokenTypeClaim = GetTokenTypeClaim(accessTokenModel); diff --git a/JwtAuthentication.Core/Contract/IJwtTokenCreator.cs b/JwtAuthentication.Core/Contract/IJwtTokenCreator.cs index ac2c366..5f74ea6 100644 --- a/JwtAuthentication.Core/Contract/IJwtTokenCreator.cs +++ b/JwtAuthentication.Core/Contract/IJwtTokenCreator.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; @@ -8,6 +7,6 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract { internal interface IJwtTokenCreator { - Task CreateAsync(string tokenType, List claims, DateTime tokenExpiresIn); + Task CreateAsync(string tokenType, int tokenLifetimeInMinutes, List claims = null); } } diff --git a/JwtAuthentication.Core/Contract/JwtTokenCreator.cs b/JwtAuthentication.Core/Contract/JwtTokenCreator.cs index 66b1a8d..f174288 100644 --- a/JwtAuthentication.Core/Contract/JwtTokenCreator.cs +++ b/JwtAuthentication.Core/Contract/JwtTokenCreator.cs @@ -19,15 +19,27 @@ public JwtTokenCreator(AuthenticationOptions authenticationOptions) _authenticationOptions = authenticationOptions; } - public async Task CreateAsync(string tokenType, List claims, DateTime tokenExpiresIn) + public async Task CreateAsync(string tokenType, int tokenLifetimeInMinutes, List claims = null) { if (!TokenType.IsAvailableTokenType(tokenType)) { throw new ArgumentException("Invalid token type value"); } + if (tokenLifetimeInMinutes <= 0) + { + throw new ArgumentException("Token lifetime cannot be negative or zero"); + } + + if (claims == null) + { + claims = new List(); + } + AddTokenTypeClaim(claims, tokenType); + var tokenExpiresIn = DateTime.UtcNow.AddMinutes(tokenLifetimeInMinutes); + var token = new JwtSecurityToken( _authenticationOptions.Issuer, _authenticationOptions.Audience, @@ -35,11 +47,9 @@ public async Task CreateAsync(string tokenType, List claims, expires: tokenExpiresIn, signingCredentials: GetCredentials()); - var tokenValue = new JwtSecurityTokenHandler().WriteToken(token); - return await Task.FromResult(new TokenModel { - Value = tokenValue, + Value = new JwtSecurityTokenHandler().WriteToken(token), ExpiresInUtc = tokenExpiresIn.ToUniversalTime(), }); } diff --git a/JwtAuthentication.Core/Services/Implementation/RefreshService.cs b/JwtAuthentication.Core/Services/Implementation/RefreshService.cs index 08de518..47319df 100644 --- a/JwtAuthentication.Core/Services/Implementation/RefreshService.cs +++ b/JwtAuthentication.Core/Services/Implementation/RefreshService.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Security.Claims; using System.Threading.Tasks; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; @@ -30,9 +28,9 @@ public async Task RefreshAsync(string tokenValue) try { await _jwtTokenValidator.ValidateTokenAsync(tokenValue); - await _jwtTokenValidator.ValidateTokenTypeAsync(tokenValue, TokenType.Refresh); + await _jwtTokenValidator.ValidateTokenTypeAsync(tokenValue, TokenType.Refresh); - return await _jwtTokenCreator.CreateAsync(TokenType.Refresh, new List(), DateTime.UtcNow.AddMinutes(_refreshTokenOptions.RefreshTokenExpireInMinutes)); + return await _jwtTokenCreator.CreateAsync(TokenType.Refresh, _refreshTokenOptions.RefreshTokenExpireInMinutes); } catch (Exception) { diff --git a/JwtAuthentication.Core/Services/Implementation/TokenManager.cs b/JwtAuthentication.Core/Services/Implementation/TokenManager.cs index 0de8e7b..6149d09 100644 --- a/JwtAuthentication.Core/Services/Implementation/TokenManager.cs +++ b/JwtAuthentication.Core/Services/Implementation/TokenManager.cs @@ -33,10 +33,7 @@ public async Task GenerateAccessTokenAsync(string login = null) ? new List() : await _userClaimsProvider.GetUserClaimsAsync(login); - return await _jwtTokenCreator.CreateAsync( - TokenType.Access, - claims, - DateTime.UtcNow.AddMinutes(_options.AccessTokenExpireInMinutes)); + return await _jwtTokenCreator.CreateAsync(TokenType.Access, _options.AccessTokenExpireInMinutes, claims); } } } \ No newline at end of file From 799a3b34cf8e9b3902d4783a905442f7a79ca79b Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Wed, 17 Aug 2022 11:15:12 +0500 Subject: [PATCH 13/34] chore: #60: implements refresh token manager for the core package --- .../AuthenticationExtensions.cs | 1 + .../Services/ICoreRefreshTokenManager.cs | 2 +- .../Implementation/CoreRefreshTokenManager.cs | 24 +++++++++++++++++++ .../Implementation/LoginWithRefreshService.cs | 5 +++- 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 JwtAuthentication.Core/Services/Implementation/CoreRefreshTokenManager.cs diff --git a/JwtAuthentication.Core/AuthenticationExtensions.cs b/JwtAuthentication.Core/AuthenticationExtensions.cs index de0d47d..2132f0b 100644 --- a/JwtAuthentication.Core/AuthenticationExtensions.cs +++ b/JwtAuthentication.Core/AuthenticationExtensions.cs @@ -92,6 +92,7 @@ public static IServiceCollection AddLoginWithRefresh( services.AddTransient(); services.AddTransient(); + services.AddTransient(); services.AddTransient(); return services; diff --git a/JwtAuthentication.Core/Services/ICoreRefreshTokenManager.cs b/JwtAuthentication.Core/Services/ICoreRefreshTokenManager.cs index 90fcc4d..d1fedb5 100644 --- a/JwtAuthentication.Core/Services/ICoreRefreshTokenManager.cs +++ b/JwtAuthentication.Core/Services/ICoreRefreshTokenManager.cs @@ -5,6 +5,6 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services { internal interface ICoreRefreshTokenManager { - Task GenerateRefreshTokenAsync(string login = null); + Task GenerateRefreshTokenAsync(); } } diff --git a/JwtAuthentication.Core/Services/Implementation/CoreRefreshTokenManager.cs b/JwtAuthentication.Core/Services/Implementation/CoreRefreshTokenManager.cs new file mode 100644 index 0000000..3f0b4ac --- /dev/null +++ b/JwtAuthentication.Core/Services/Implementation/CoreRefreshTokenManager.cs @@ -0,0 +1,24 @@ +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation +{ + internal class CoreRefreshTokenManager : ICoreRefreshTokenManager + { + private readonly IJwtTokenCreator _jwtTokenCreator; + private readonly RefreshTokenOptions _refreshTokenOptions; + + public CoreRefreshTokenManager(IJwtTokenCreator jwtTokenCreator, RefreshTokenOptions refreshTokenOptions) + { + _jwtTokenCreator = jwtTokenCreator; + _refreshTokenOptions = refreshTokenOptions; + } + + public Task GenerateRefreshTokenAsync() + { + return _jwtTokenCreator.CreateAsync(TokenType.Refresh, _refreshTokenOptions.RefreshTokenExpireInMinutes); + } + } +} diff --git a/JwtAuthentication.Core/Services/Implementation/LoginWithRefreshService.cs b/JwtAuthentication.Core/Services/Implementation/LoginWithRefreshService.cs index 22e0e7d..9926bcf 100644 --- a/JwtAuthentication.Core/Services/Implementation/LoginWithRefreshService.cs +++ b/JwtAuthentication.Core/Services/Implementation/LoginWithRefreshService.cs @@ -8,13 +8,16 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementati internal class LoginWithRefreshService : LoginService { private readonly ITokenManager _tokenManager; + private readonly ICoreRefreshTokenManager _refreshTokenManager; public LoginWithRefreshService( ITokenManager tokenManager, + ICoreRefreshTokenManager refreshTokenManager, IUserCredentialsValidator userCredentialsValidator = null) : base(tokenManager, userCredentialsValidator) { _tokenManager = tokenManager; + _refreshTokenManager = refreshTokenManager; } public override async Task LoginAsync(LoginRequestModel model) @@ -24,7 +27,7 @@ public override async Task LoginAsync(LoginRequestModel model return new AuthResponseModel { AccessToken = await _tokenManager.GenerateAccessTokenAsync(model.Login), - RefreshToken = await _tokenManager.GenerateAccessTokenAsync(model.Login), + RefreshToken = await _refreshTokenManager.GenerateRefreshTokenAsync(), }; } } From f8ba385495e1d297409a5fdfc7a4eeef5ee3e09c Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Wed, 17 Aug 2022 11:47:52 +0500 Subject: [PATCH 14/34] build(examples): #60: adds a project example for the refresh feature --- AspNetCore.JwtAuthentication.sln | 7 +++ .../Controllers/ExampleController.cs | 32 +++++++++++++ ...e3.1.AuthenticationWithRefreshToken.csproj | 13 +++++ .../Program.cs | 19 ++++++++ .../Properties/launchSettings.json | 29 ++++++++++++ .../Startup.cs | 47 +++++++++++++++++++ .../appsettings.json | 7 +++ 7 files changed, 154 insertions(+) create mode 100644 Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Controllers/ExampleController.cs create mode 100644 Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Example.NetCore3.1.AuthenticationWithRefreshToken.csproj create mode 100644 Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Program.cs create mode 100644 Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Properties/launchSettings.json create mode 100644 Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Startup.cs create mode 100644 Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/appsettings.json diff --git a/AspNetCore.JwtAuthentication.sln b/AspNetCore.JwtAuthentication.sln index e1ce8a8..5a6943c 100644 --- a/AspNetCore.JwtAuthentication.sln +++ b/AspNetCore.JwtAuthentication.sln @@ -60,6 +60,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore6.0.RefreshT EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore5.0.RefreshTokenWithConfidenceInterval", "Examples\Example.NetCore5.0.RefreshTokenWithConfidenceInterval\Example.NetCore5.0.RefreshTokenWithConfidenceInterval.csproj", "{F0E28B79-7957-444F-B437-D2EEC072A6DE}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.NetCore3.1.AuthenticationWithRefreshToken", "Examples\Example.NetCore3.1.AuthenticationWithRefreshToken\Example.NetCore3.1.AuthenticationWithRefreshToken.csproj", "{63E8464D-8489-4423-ADCD-1107DC5D9336}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -154,6 +156,10 @@ Global {F0E28B79-7957-444F-B437-D2EEC072A6DE}.Debug|Any CPU.Build.0 = Debug|Any CPU {F0E28B79-7957-444F-B437-D2EEC072A6DE}.Release|Any CPU.ActiveCfg = Release|Any CPU {F0E28B79-7957-444F-B437-D2EEC072A6DE}.Release|Any CPU.Build.0 = Release|Any CPU + {63E8464D-8489-4423-ADCD-1107DC5D9336}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {63E8464D-8489-4423-ADCD-1107DC5D9336}.Debug|Any CPU.Build.0 = Debug|Any CPU + {63E8464D-8489-4423-ADCD-1107DC5D9336}.Release|Any CPU.ActiveCfg = Release|Any CPU + {63E8464D-8489-4423-ADCD-1107DC5D9336}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -182,6 +188,7 @@ Global {C617F7DD-6E7E-4B5D-8766-C82C37EFFF6E} = {4FF83CB3-A634-4D07-BEE0-B5391B86F071} {ABDD94F3-DF9E-47B2-813F-935C54C8DEA7} = {4FF83CB3-A634-4D07-BEE0-B5391B86F071} {F0E28B79-7957-444F-B437-D2EEC072A6DE} = {7A925031-2656-4CEB-821A-D76739E0E5A2} + {63E8464D-8489-4423-ADCD-1107DC5D9336} = {614DB4C6-A4BE-4BBF-B385-C34985CA1FC3} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C2026BF9-DACC-4EA4-AF04-B8A590EA38BF} diff --git a/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Controllers/ExampleController.cs b/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Controllers/ExampleController.cs new file mode 100644 index 0000000..b0c214b --- /dev/null +++ b/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Controllers/ExampleController.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Example.NetCore3._1.AuthenticationWithRefreshToken.Controllers +{ + [ApiController] + [Route("[controller]")] + public class ExampleController : ControllerBase + { + private static readonly string[] Summaries = + { + "Freezing", + "Bracing", + "Chilly", + "Cool", + "Mild", + "Warm", + "Balmy", + "Hot", + "Sweltering", + "Scorching", + }; + + [Authorize] + [HttpGet] + public IEnumerable Get() + { + return Summaries; + } + } +} \ No newline at end of file diff --git a/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Example.NetCore3.1.AuthenticationWithRefreshToken.csproj b/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Example.NetCore3.1.AuthenticationWithRefreshToken.csproj new file mode 100644 index 0000000..9f29a51 --- /dev/null +++ b/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Example.NetCore3.1.AuthenticationWithRefreshToken.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + Example.NetCore3._1.AuthenticationWithRefreshToken + + + + + + + + diff --git a/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Program.cs b/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Program.cs new file mode 100644 index 0000000..4876d06 --- /dev/null +++ b/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Program.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace Example.NetCore3._1.AuthenticationWithRefreshToken +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) + { + return Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); + } + } +} diff --git a/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Properties/launchSettings.json b/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Properties/launchSettings.json new file mode 100644 index 0000000..da1a230 --- /dev/null +++ b/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:36255", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "weatherforecast", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Example.NetCore3._1.AuthenticationWithRefreshToken": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:5000" + } + } +} diff --git a/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Startup.cs b/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Startup.cs new file mode 100644 index 0000000..0e7d0f1 --- /dev/null +++ b/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Startup.cs @@ -0,0 +1,47 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using TourmalineCore.AspNetCore.JwtAuthentication.Core; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; + +namespace Example.NetCore3._1.AuthenticationWithRefreshToken +{ + public class Startup + { + private readonly IConfiguration _configuration; + + public Startup(IConfiguration configuration) + { + _configuration = configuration; + } + + public void ConfigureServices(IServiceCollection services) + { + services + .AddJwtAuthentication(_configuration.GetSection(nameof(AuthenticationOptions)).Get()) + .AddLoginWithRefresh(); + + services.AddControllers(); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + + app + .UseDefaultLoginMiddleware() + .UseJwtAuthentication(); + + app.UseRefreshTokenMiddleware(); + + app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); + } + } +} diff --git a/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/appsettings.json b/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/appsettings.json new file mode 100644 index 0000000..aeb23f9 --- /dev/null +++ b/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/appsettings.json @@ -0,0 +1,7 @@ +{ + "AuthenticationOptions": { + "PublicSigningKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQAB", + "PrivateSigningKey": "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU", + "AccessTokenExpireInMinutes": 15 + } +} \ No newline at end of file From c2f332b9c81377fa11f9dcc721abcce00dea47de Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Thu, 18 Aug 2022 09:56:36 +0500 Subject: [PATCH 15/34] chore(middlewares): #60: adds errors handling on different exceptions --- .../ErrorHandling/AuthenticationException.cs | 14 -------- .../ErrorHandling/ErrorTypes.cs | 17 --------- .../IncorrectLoginOrPasswordException.cs | 9 +++++ .../ErrorHandling/InvalidJwtTokenException.cs | 9 +++++ ...TokenIsNotInConfidenceIntervalException.cs | 9 +++++ .../RefreshTokenNotFoundException.cs | 9 +++++ ...reshTokenOrFingerprintNotFoundException.cs | 9 +++++ .../ErrorHandling/RegistrationException.cs | 3 +- .../Middlewares/Login/LoginMiddleware.cs | 6 ++-- .../Middlewares/LoginWithCookieMiddleware.cs | 6 ++-- .../Middlewares/Refresh/RefreshMiddleware.cs | 12 +++---- .../Middlewares/RequestMiddlewareBase.cs | 36 +++++++++++++------ .../Services/Implementation/LoginService.cs | 4 +-- .../Services/Implementation/RefreshService.cs | 2 +- .../Middleware/Logout/LogoutMiddleware.cs | 3 +- .../Middleware/Refresh/RefreshMiddleware.cs | 2 +- .../Registration/RegistrationMiddleware.cs | 1 + .../Services/IdentityLoginService.cs | 4 +-- .../Services/IdentityRefreshLoginService.cs | 8 ++--- .../Services/RefreshTokenManager.cs | 2 +- .../Validators/RefreshTokenValidator.cs | 4 +-- 21 files changed, 100 insertions(+), 69 deletions(-) delete mode 100644 JwtAuthentication.Core/ErrorHandling/AuthenticationException.cs delete mode 100644 JwtAuthentication.Core/ErrorHandling/ErrorTypes.cs create mode 100644 JwtAuthentication.Core/ErrorHandling/IncorrectLoginOrPasswordException.cs create mode 100644 JwtAuthentication.Core/ErrorHandling/InvalidJwtTokenException.cs create mode 100644 JwtAuthentication.Core/ErrorHandling/RefreshTokenIsNotInConfidenceIntervalException.cs create mode 100644 JwtAuthentication.Core/ErrorHandling/RefreshTokenNotFoundException.cs create mode 100644 JwtAuthentication.Core/ErrorHandling/RefreshTokenOrFingerprintNotFoundException.cs diff --git a/JwtAuthentication.Core/ErrorHandling/AuthenticationException.cs b/JwtAuthentication.Core/ErrorHandling/AuthenticationException.cs deleted file mode 100644 index 15ee0c3..0000000 --- a/JwtAuthentication.Core/ErrorHandling/AuthenticationException.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling -{ - public class AuthenticationException : Exception - { - public AuthenticationException(ErrorTypes errorType) - { - ExceptionInfo = errorType; - } - - public ErrorTypes ExceptionInfo { get; } - } -} \ No newline at end of file diff --git a/JwtAuthentication.Core/ErrorHandling/ErrorTypes.cs b/JwtAuthentication.Core/ErrorHandling/ErrorTypes.cs deleted file mode 100644 index 596456d..0000000 --- a/JwtAuthentication.Core/ErrorHandling/ErrorTypes.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling -{ - public enum ErrorTypes - { - IncorrectLoginOrPassword = 0, - RefreshTokenNotFound, - IncorrectActivationLink, - DuplicateActivationLink, - IncorrectResetPasswordLink, - InvalidPasswordFormat, - UserNotFound, - ReCaptchaTokenIncorrect, - RefreshTokenOrFingerprintNotFound, - RefreshTokenIsNotInConfidenceInterval, - InvalidJwtToken, - } -} \ No newline at end of file diff --git a/JwtAuthentication.Core/ErrorHandling/IncorrectLoginOrPasswordException.cs b/JwtAuthentication.Core/ErrorHandling/IncorrectLoginOrPasswordException.cs new file mode 100644 index 0000000..f5f7f3c --- /dev/null +++ b/JwtAuthentication.Core/ErrorHandling/IncorrectLoginOrPasswordException.cs @@ -0,0 +1,9 @@ +using System; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling +{ + public class IncorrectLoginOrPasswordException : Exception + { + public IncorrectLoginOrPasswordException() : base("Incorrect login or password") { } + } +} diff --git a/JwtAuthentication.Core/ErrorHandling/InvalidJwtTokenException.cs b/JwtAuthentication.Core/ErrorHandling/InvalidJwtTokenException.cs new file mode 100644 index 0000000..1d8d2fc --- /dev/null +++ b/JwtAuthentication.Core/ErrorHandling/InvalidJwtTokenException.cs @@ -0,0 +1,9 @@ +using System; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling +{ + public class InvalidJwtTokenException : Exception + { + public InvalidJwtTokenException() : base("Invalid jwt token") { } + } +} diff --git a/JwtAuthentication.Core/ErrorHandling/RefreshTokenIsNotInConfidenceIntervalException.cs b/JwtAuthentication.Core/ErrorHandling/RefreshTokenIsNotInConfidenceIntervalException.cs new file mode 100644 index 0000000..f683dec --- /dev/null +++ b/JwtAuthentication.Core/ErrorHandling/RefreshTokenIsNotInConfidenceIntervalException.cs @@ -0,0 +1,9 @@ +using System; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling +{ + public class RefreshTokenIsNotInConfidenceIntervalException : Exception + { + public RefreshTokenIsNotInConfidenceIntervalException() : base("Refresh token is not in confidence interval") { } + } +} diff --git a/JwtAuthentication.Core/ErrorHandling/RefreshTokenNotFoundException.cs b/JwtAuthentication.Core/ErrorHandling/RefreshTokenNotFoundException.cs new file mode 100644 index 0000000..c17a1d6 --- /dev/null +++ b/JwtAuthentication.Core/ErrorHandling/RefreshTokenNotFoundException.cs @@ -0,0 +1,9 @@ +using System; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling +{ + internal class RefreshTokenNotFoundException : Exception + { + public RefreshTokenNotFoundException() : base("Refresh token not found") { } + } +} diff --git a/JwtAuthentication.Core/ErrorHandling/RefreshTokenOrFingerprintNotFoundException.cs b/JwtAuthentication.Core/ErrorHandling/RefreshTokenOrFingerprintNotFoundException.cs new file mode 100644 index 0000000..06aa60a --- /dev/null +++ b/JwtAuthentication.Core/ErrorHandling/RefreshTokenOrFingerprintNotFoundException.cs @@ -0,0 +1,9 @@ +using System; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling +{ + public class RefreshTokenOrFingerprintNotFoundException : Exception + { + public RefreshTokenOrFingerprintNotFoundException() : base("Refresh token or fingerprint not found") { } + } +} diff --git a/JwtAuthentication.Core/ErrorHandling/RegistrationException.cs b/JwtAuthentication.Core/ErrorHandling/RegistrationException.cs index 502933e..85c6f29 100644 --- a/JwtAuthentication.Core/ErrorHandling/RegistrationException.cs +++ b/JwtAuthentication.Core/ErrorHandling/RegistrationException.cs @@ -3,6 +3,7 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling { public class RegistrationException : Exception - { + { + public RegistrationException() : base("An registration exception occured") { } } } \ No newline at end of file diff --git a/JwtAuthentication.Core/Middlewares/Login/LoginMiddleware.cs b/JwtAuthentication.Core/Middlewares/Login/LoginMiddleware.cs index 4362437..0f007f3 100644 --- a/JwtAuthentication.Core/Middlewares/Login/LoginMiddleware.cs +++ b/JwtAuthentication.Core/Middlewares/Login/LoginMiddleware.cs @@ -1,7 +1,6 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; @@ -50,9 +49,10 @@ protected override async Task ExecuteServiceMethod( result = await service.LoginAsync(requestModel); await _onLoginExecuted(contractLoginModel); } - catch (AuthenticationException) + catch (Exception ex) { - context.Response.StatusCode = StatusCodes.Status401Unauthorized; + context.Response.StatusCode = StatusCodes.Status401Unauthorized; + throw new Exception(ex.Message); } return result; diff --git a/JwtAuthentication.Core/Middlewares/LoginWithCookieMiddleware.cs b/JwtAuthentication.Core/Middlewares/LoginWithCookieMiddleware.cs index 7900581..8ed00a4 100644 --- a/JwtAuthentication.Core/Middlewares/LoginWithCookieMiddleware.cs +++ b/JwtAuthentication.Core/Middlewares/LoginWithCookieMiddleware.cs @@ -1,3 +1,4 @@ +using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; @@ -51,9 +52,10 @@ protected override async Task ExecuteServiceMethod( ); } } - catch (AuthenticationException) + catch (Exception ex) { - context.Response.StatusCode = StatusCodes.Status401Unauthorized; + context.Response.StatusCode = StatusCodes.Status401Unauthorized; + throw new Exception(ex.Message); } return new AuthResponseModel(); diff --git a/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs b/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs index a01ab88..82931d4 100644 --- a/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs +++ b/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs @@ -1,8 +1,7 @@ -using System; +using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; @@ -56,10 +55,11 @@ protected override async Task ExecuteServiceMethod( result = await service.RefreshAsync(contractRefreshModel.RefreshTokenValue); await _onRefreshExecuted(contractRefreshModel); } - catch (AuthenticationException ex) - { - context.Response.StatusCode = StatusCodes.Status409Conflict; - _logger.LogError(ex.ToString()); + catch (Exception ex) + { + context.Response.StatusCode = StatusCodes.Status409Conflict; + _logger.LogError(ex.ToString()); + throw new Exception(ex.Message); } return result; diff --git a/JwtAuthentication.Core/Middlewares/RequestMiddlewareBase.cs b/JwtAuthentication.Core/Middlewares/RequestMiddlewareBase.cs index 83069b8..66df5d0 100644 --- a/JwtAuthentication.Core/Middlewares/RequestMiddlewareBase.cs +++ b/JwtAuthentication.Core/Middlewares/RequestMiddlewareBase.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -55,28 +56,41 @@ protected RequestMiddlewareBase(RequestDelegate next) protected async Task InvokeAsyncBase(HttpContext context, TService service, string endpointRoute) { - if (context.Request.Method == HttpMethods.Post) + try { - var endpoint = context.Request.Path.Value; - - if (endpoint.EndsWith(endpointRoute)) + if (context.Request.Method == HttpMethods.Post) { - var requestModel = await DeserializeModel(context.Request); - - var result = await ExecuteServiceMethod(requestModel, service, context); + var endpoint = context.Request.Path.Value; - if (result != null) + if (endpoint.EndsWith(endpointRoute)) { - await Response(context, result); - return; + var requestModel = await DeserializeModel(context.Request); + + var result = await ExecuteServiceMethod(requestModel, service, context); + + if (result != null) + { + await Response(context, result); + return; + } } } } + catch (Exception ex) + { + var errorModelExample = new + { + ErrorMessage = ex.Message, + }; + + await Response(context, errorModelExample); + return; + } await _next(context); } - private async Task Response(HttpContext context, TResponseModel result) + private async Task Response(HttpContext context, T result) { context.Response.ContentType = "application/json; charset=UTF-8"; #if NETCOREAPP3_0 || NETCOREAPP3_1 diff --git a/JwtAuthentication.Core/Services/Implementation/LoginService.cs b/JwtAuthentication.Core/Services/Implementation/LoginService.cs index 375b6eb..752a4b5 100644 --- a/JwtAuthentication.Core/Services/Implementation/LoginService.cs +++ b/JwtAuthentication.Core/Services/Implementation/LoginService.cs @@ -36,8 +36,8 @@ protected virtual async Task ValidateCredentials(LoginRequestModel model) var isUserCredentialsValid = await _userCredentialsValidator.ValidateUserCredentials(model.Login, model.Password); if (!isUserCredentialsValid) - { - throw new AuthenticationException(ErrorTypes.IncorrectLoginOrPassword); + { + throw new IncorrectLoginOrPasswordException(); } } } diff --git a/JwtAuthentication.Core/Services/Implementation/RefreshService.cs b/JwtAuthentication.Core/Services/Implementation/RefreshService.cs index 47319df..f6a3625 100644 --- a/JwtAuthentication.Core/Services/Implementation/RefreshService.cs +++ b/JwtAuthentication.Core/Services/Implementation/RefreshService.cs @@ -34,7 +34,7 @@ public async Task RefreshAsync(string tokenValue) } catch (Exception) { - throw new AuthenticationException(ErrorTypes.InvalidJwtToken); + throw new InvalidJwtTokenException(); } } } diff --git a/JwtAuthentication.Identity/Middleware/Logout/LogoutMiddleware.cs b/JwtAuthentication.Identity/Middleware/Logout/LogoutMiddleware.cs index fff1f89..b93f52d 100644 --- a/JwtAuthentication.Identity/Middleware/Logout/LogoutMiddleware.cs +++ b/JwtAuthentication.Identity/Middleware/Logout/LogoutMiddleware.cs @@ -1,5 +1,4 @@ using System; -using System.Security.Authentication; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; @@ -55,7 +54,7 @@ protected override async Task ExecuteServiceMethod( await service.LogoutAsync(requestModel); await _onLogoutExecuted(contractLogoutModel); } - catch (AuthenticationException ex) + catch (Exception ex) { context.Response.StatusCode = StatusCodes.Status409Conflict; _logger.LogError(ex.ToString()); diff --git a/JwtAuthentication.Identity/Middleware/Refresh/RefreshMiddleware.cs b/JwtAuthentication.Identity/Middleware/Refresh/RefreshMiddleware.cs index 4dde006..6ac9778 100644 --- a/JwtAuthentication.Identity/Middleware/Refresh/RefreshMiddleware.cs +++ b/JwtAuthentication.Identity/Middleware/Refresh/RefreshMiddleware.cs @@ -58,7 +58,7 @@ protected override async Task ExecuteServiceMethod( result = await service.RefreshAsync(contractRefreshModel.RefreshTokenValue, contractRefreshModel.ClientFingerPrint); await _onRefreshExecuted(contractRefreshModel); } - catch (AuthenticationException ex) + catch (Exception ex) { context.Response.StatusCode = StatusCodes.Status409Conflict; _logger.LogError(ex.ToString()); diff --git a/JwtAuthentication.Identity/Middleware/Registration/RegistrationMiddleware.cs b/JwtAuthentication.Identity/Middleware/Registration/RegistrationMiddleware.cs index 1eeff09..c6a4b93 100644 --- a/JwtAuthentication.Identity/Middleware/Registration/RegistrationMiddleware.cs +++ b/JwtAuthentication.Identity/Middleware/Registration/RegistrationMiddleware.cs @@ -83,6 +83,7 @@ protected override async Task ExecuteServiceMethod( { context.Response.StatusCode = StatusCodes.Status409Conflict; _logger.LogError(ex.ToString()); + throw new Exception(ex.Message); } return result; diff --git a/JwtAuthentication.Identity/Services/IdentityLoginService.cs b/JwtAuthentication.Identity/Services/IdentityLoginService.cs index f2ccee4..4f196d6 100644 --- a/JwtAuthentication.Identity/Services/IdentityLoginService.cs +++ b/JwtAuthentication.Identity/Services/IdentityLoginService.cs @@ -37,14 +37,14 @@ public async Task LoginAsync(LoginRequestModel model) if (user is null) { - throw new AuthenticationException(ErrorTypes.IncorrectLoginOrPassword); + throw new IncorrectLoginOrPasswordException(); } var passwordIsCorrect = await _signInManager.UserManager.CheckPasswordAsync(user, model.Password); if (passwordIsCorrect == false) { - throw new AuthenticationException(ErrorTypes.IncorrectLoginOrPassword); + throw new IncorrectLoginOrPasswordException(); } var token = await _tokenManager.GenerateAccessTokenAsync( diff --git a/JwtAuthentication.Identity/Services/IdentityRefreshLoginService.cs b/JwtAuthentication.Identity/Services/IdentityRefreshLoginService.cs index cccf917..dabd63f 100644 --- a/JwtAuthentication.Identity/Services/IdentityRefreshLoginService.cs +++ b/JwtAuthentication.Identity/Services/IdentityRefreshLoginService.cs @@ -59,7 +59,7 @@ public async Task LoginAsync(LoginRequestModel model) if (signInResult == false) { - throw new AuthenticationException(ErrorTypes.IncorrectLoginOrPassword); + throw new IncorrectLoginOrPasswordException(); } var user = await _signInManager.UserManager.FindByNameAsync(model.Login); @@ -100,9 +100,9 @@ private async Task GenerateAuthTokensWhenRefreshConfidenceInt if (refreshTokenIsInConfidenceInterval) { return await _signInManager.GenerateAuthTokens(user, clientFingerPrint); - } - - throw new AuthenticationException(ErrorTypes.RefreshTokenIsNotInConfidenceInterval); + } + + throw new RefreshTokenIsNotInConfidenceIntervalException(); } } } \ No newline at end of file diff --git a/JwtAuthentication.Identity/Services/RefreshTokenManager.cs b/JwtAuthentication.Identity/Services/RefreshTokenManager.cs index 5077084..10d4328 100644 --- a/JwtAuthentication.Identity/Services/RefreshTokenManager.cs +++ b/JwtAuthentication.Identity/Services/RefreshTokenManager.cs @@ -140,7 +140,7 @@ private static void ThrowExceptionIfTokenIsNull(RefreshToken token) { if (token == null) { - throw new AuthenticationException(ErrorTypes.RefreshTokenNotFound); + throw new RefreshTokenNotFoundException(); } } } diff --git a/JwtAuthentication.Identity/Validators/RefreshTokenValidator.cs b/JwtAuthentication.Identity/Validators/RefreshTokenValidator.cs index 8444c3d..29f4a4d 100644 --- a/JwtAuthentication.Identity/Validators/RefreshTokenValidator.cs +++ b/JwtAuthentication.Identity/Validators/RefreshTokenValidator.cs @@ -14,8 +14,8 @@ public Task ValidateAsync(RefreshTokenRequestModel model) private void InternalValidate(RefreshTokenRequestModel model) { if (model == null || model.RefreshTokenValue == default) - { - throw new AuthenticationException(ErrorTypes.RefreshTokenOrFingerprintNotFound); + { + throw new RefreshTokenOrFingerprintNotFoundException(); } } } From 2e496c38bec0bab6b7b982c5ff3d5fc621362749 Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Thu, 18 Aug 2022 11:03:18 +0500 Subject: [PATCH 16/34] chore: #60: adds shared library to use refresh feature in the both projects --- AspNetCore.JwtAuthentication.sln | 8 +- .../Startup.cs | 3 +- .../Program.cs | 2 +- .../ApplicationBuilderExtension.cs | 36 +++++- .../Refresh/IRefreshMiddlewareBuilder.cs | 2 +- .../ApplicationBuilderExtensions.cs | 46 ------- .../ApplicationBuilderExtension.cs | 54 ++++++++ JwtAuthentication.Shared/Consts.cs | 7 ++ .../Exceptions/InvalidJwtTokenException.cs | 9 ++ .../JwtAuthentication.Shared.csproj | 22 ++++ .../Refresh/IRefreshMiddlewareBuilder.cs | 17 +++ .../Refresh/Models/RefreshModel.cs | 7 ++ .../Middlewares/Refresh/RefreshMiddleware.cs | 68 ++++++++++ .../Refresh/RefreshMiddlewareBuilder.cs | 73 +++++++++++ .../Middlewares/RequestMiddlewareBase.cs | 118 ++++++++++++++++++ .../Requests/CoreRefreshTokenRequest.cs | 9 ++ JwtAuthentication.Shared/Models/TokenModel.cs | 14 +++ JwtAuthentication.Shared/Models/TokenType.cs | 13 ++ .../Options/AuthenticationOptions.cs | 23 ++++ .../Options/RefreshEndpointOptions.cs | 13 ++ .../Options/RefreshTokenOptions.cs | 13 ++ .../Services/Contracts/ICoreRefreshService.cs | 10 ++ .../Services/CoreRefreshService.cs | 42 +++++++ .../Signing/SigningHelper.cs | 29 +++++ .../Contracts/IJwtTokenCreator.cs | 12 ++ .../Contracts/IJwtTokenValidator.cs | 10 ++ .../TokenServices/JwtTokenCreator.cs | 75 +++++++++++ .../TokenServices/JwtTokenValidator.cs | 61 +++++++++ 28 files changed, 742 insertions(+), 54 deletions(-) create mode 100644 JwtAuthentication.Shared/ApplicationBuilderExtension.cs create mode 100644 JwtAuthentication.Shared/Consts.cs create mode 100644 JwtAuthentication.Shared/Exceptions/InvalidJwtTokenException.cs create mode 100644 JwtAuthentication.Shared/JwtAuthentication.Shared.csproj create mode 100644 JwtAuthentication.Shared/Middlewares/Refresh/IRefreshMiddlewareBuilder.cs create mode 100644 JwtAuthentication.Shared/Middlewares/Refresh/Models/RefreshModel.cs create mode 100644 JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddleware.cs create mode 100644 JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddlewareBuilder.cs create mode 100644 JwtAuthentication.Shared/Middlewares/RequestMiddlewareBase.cs create mode 100644 JwtAuthentication.Shared/Models/Requests/CoreRefreshTokenRequest.cs create mode 100644 JwtAuthentication.Shared/Models/TokenModel.cs create mode 100644 JwtAuthentication.Shared/Models/TokenType.cs create mode 100644 JwtAuthentication.Shared/Options/AuthenticationOptions.cs create mode 100644 JwtAuthentication.Shared/Options/RefreshEndpointOptions.cs create mode 100644 JwtAuthentication.Shared/Options/RefreshTokenOptions.cs create mode 100644 JwtAuthentication.Shared/Services/Contracts/ICoreRefreshService.cs create mode 100644 JwtAuthentication.Shared/Services/CoreRefreshService.cs create mode 100644 JwtAuthentication.Shared/Signing/SigningHelper.cs create mode 100644 JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenCreator.cs create mode 100644 JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenValidator.cs create mode 100644 JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs create mode 100644 JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs diff --git a/AspNetCore.JwtAuthentication.sln b/AspNetCore.JwtAuthentication.sln index 5a6943c..120834c 100644 --- a/AspNetCore.JwtAuthentication.sln +++ b/AspNetCore.JwtAuthentication.sln @@ -60,7 +60,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore6.0.RefreshT EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore5.0.RefreshTokenWithConfidenceInterval", "Examples\Example.NetCore5.0.RefreshTokenWithConfidenceInterval\Example.NetCore5.0.RefreshTokenWithConfidenceInterval.csproj", "{F0E28B79-7957-444F-B437-D2EEC072A6DE}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.NetCore3.1.AuthenticationWithRefreshToken", "Examples\Example.NetCore3.1.AuthenticationWithRefreshToken\Example.NetCore3.1.AuthenticationWithRefreshToken.csproj", "{63E8464D-8489-4423-ADCD-1107DC5D9336}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore3.1.AuthenticationWithRefreshToken", "Examples\Example.NetCore3.1.AuthenticationWithRefreshToken\Example.NetCore3.1.AuthenticationWithRefreshToken.csproj", "{63E8464D-8489-4423-ADCD-1107DC5D9336}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JwtAuthentication.Shared", "JwtAuthentication.Shared\JwtAuthentication.Shared.csproj", "{E1952561-A7CD-45C3-B9D0-AC9B92A194CC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -160,6 +162,10 @@ Global {63E8464D-8489-4423-ADCD-1107DC5D9336}.Debug|Any CPU.Build.0 = Debug|Any CPU {63E8464D-8489-4423-ADCD-1107DC5D9336}.Release|Any CPU.ActiveCfg = Release|Any CPU {63E8464D-8489-4423-ADCD-1107DC5D9336}.Release|Any CPU.Build.0 = Release|Any CPU + {E1952561-A7CD-45C3-B9D0-AC9B92A194CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1952561-A7CD-45C3-B9D0-AC9B92A194CC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1952561-A7CD-45C3-B9D0-AC9B92A194CC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1952561-A7CD-45C3-B9D0-AC9B92A194CC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Examples/Example.NetCore5.0.AuthenticationWithRefreshToken/Startup.cs b/Examples/Example.NetCore5.0.AuthenticationWithRefreshToken/Startup.cs index c47135a..a47c555 100644 --- a/Examples/Example.NetCore5.0.AuthenticationWithRefreshToken/Startup.cs +++ b/Examples/Example.NetCore5.0.AuthenticationWithRefreshToken/Startup.cs @@ -8,9 +8,10 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using TourmalineCore.AspNetCore.JwtAuthentication.Core; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Identity; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Logout.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Refresh.Models; +//using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Refresh.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options; namespace Example.NetCore5._0.AuthenticationWithRefreshToken diff --git a/Examples/Example.NetCore6.0.AuthenticationWithRefreshToken/Program.cs b/Examples/Example.NetCore6.0.AuthenticationWithRefreshToken/Program.cs index cf09a1c..595faf8 100644 --- a/Examples/Example.NetCore6.0.AuthenticationWithRefreshToken/Program.cs +++ b/Examples/Example.NetCore6.0.AuthenticationWithRefreshToken/Program.cs @@ -2,9 +2,9 @@ using Example.NetCore6._0.AuthenticationWithRefreshToken.Models; using Microsoft.EntityFrameworkCore; using TourmalineCore.AspNetCore.JwtAuthentication.Core; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Identity; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Logout.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Refresh.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options; var builder = WebApplication.CreateBuilder(args); diff --git a/JwtAuthentication.Core/ApplicationBuilderExtension.cs b/JwtAuthentication.Core/ApplicationBuilderExtension.cs index 9f651ef..66c06ef 100644 --- a/JwtAuthentication.Core/ApplicationBuilderExtension.cs +++ b/JwtAuthentication.Core/ApplicationBuilderExtension.cs @@ -4,8 +4,8 @@ using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core @@ -77,8 +77,8 @@ public static IDefaultLoginMiddlewareBuilder OnLoginExecuted(this IApplicationBu .GetInstance() .SetAppBuilder(applicationBuilder) .OnLoginExecuted(callback); - } - + } + /// /// Adds middleware to handle incoming login and token refresh requests. /// @@ -91,6 +91,34 @@ public static IApplicationBuilder UseRefreshTokenMiddleware(this IApplicationBui return applicationBuilder .UseMiddleware(endpointOptions ?? new RefreshEndpointOptions(), defaultOnRefreshCallback, defaultOnRefreshCallback); + } + + /// + /// Registering a callback function to perform actions when when the refresh starts. + /// + /// + /// + /// + public static IRefreshMiddlewareBuilder OnRefreshExecuting(this IApplicationBuilder applicationBuilder, Func callback) + { + return RefreshMiddlewareBuilder + .GetInstance() + .SetAppBuilder(applicationBuilder) + .OnRefreshExecuting(callback); + } + + /// + /// Registering a callback function to perform actions when the refresh ends. + /// + /// + /// + /// + public static IRefreshMiddlewareBuilder OnRefreshExecuted(this IApplicationBuilder applicationBuilder, Func callback) + { + return RefreshMiddlewareBuilder + .GetInstance() + .SetAppBuilder(applicationBuilder) + .OnRefreshExecuted(callback); } } } \ No newline at end of file diff --git a/JwtAuthentication.Core/Middlewares/Refresh/IRefreshMiddlewareBuilder.cs b/JwtAuthentication.Core/Middlewares/Refresh/IRefreshMiddlewareBuilder.cs index f47cdd1..4a1acd7 100644 --- a/JwtAuthentication.Core/Middlewares/Refresh/IRefreshMiddlewareBuilder.cs +++ b/JwtAuthentication.Core/Middlewares/Refresh/IRefreshMiddlewareBuilder.cs @@ -1,7 +1,7 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh diff --git a/JwtAuthentication.Identity/ApplicationBuilderExtensions.cs b/JwtAuthentication.Identity/ApplicationBuilderExtensions.cs index 1b20566..4275058 100644 --- a/JwtAuthentication.Identity/ApplicationBuilderExtensions.cs +++ b/JwtAuthentication.Identity/ApplicationBuilderExtensions.cs @@ -6,13 +6,9 @@ using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Logout; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Logout.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Refresh; -using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Refresh.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Registration; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Registration.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options; -using IRefreshMiddlewareBuilder = TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Refresh.IRefreshMiddlewareBuilder; -using RefreshMiddlewareBuilder = TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Refresh.RefreshMiddlewareBuilder; namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity { @@ -92,20 +88,6 @@ public static IApplicationBuilder UseDefaultDbUser( .UseAuthorization(); } - ///// - ///// Adds middleware to handle incoming login and token refresh requests. - ///// - ///// - ///// - ///// - //public static IApplicationBuilder UseRefreshTokenMiddleware(this IApplicationBuilder applicationBuilder, RefreshEndpointOptions endpointOptions = null) - //{ - // Func defaultOnRefreshCallback = s => Task.CompletedTask; - - // return applicationBuilder - // .UseMiddleware(endpointOptions ?? new RefreshEndpointOptions(), defaultOnRefreshCallback, defaultOnRefreshCallback); - //} - /// /// Adds middleware to handle incoming user registration requests. It requires a function to map model received from client /// to user entity. @@ -248,34 +230,6 @@ public static ILogoutMiddlewareBuilder OnLogoutExecuted(this IApplicationBuilder .OnLogoutExecuted(callback); } - /// - /// Registering a callback function to perform actions when when the refresh starts. - /// - /// - /// - /// - public static IRefreshMiddlewareBuilder OnRefreshExecuting(this IApplicationBuilder applicationBuilder, Func callback) - { - return RefreshMiddlewareBuilder - .GetInstance() - .SetAppBuilder(applicationBuilder) - .OnRefreshExecuting(callback); - } - - /// - /// Registering a callback function to perform actions when the refresh ends. - /// - /// - /// - /// - public static IRefreshMiddlewareBuilder OnRefreshExecuted(this IApplicationBuilder applicationBuilder, Func callback) - { - return RefreshMiddlewareBuilder - .GetInstance() - .SetAppBuilder(applicationBuilder) - .OnRefreshExecuted(callback); - } - /// /// Registering a callback function to perform actions when when the refresh starts. /// diff --git a/JwtAuthentication.Shared/ApplicationBuilderExtension.cs b/JwtAuthentication.Shared/ApplicationBuilderExtension.cs new file mode 100644 index 0000000..8d76098 --- /dev/null +++ b/JwtAuthentication.Shared/ApplicationBuilderExtension.cs @@ -0,0 +1,54 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared +{ + public static class ApplicationBuilderExtension + { + /// + /// Adds middleware to handle incoming login and token refresh requests. + /// + /// + /// + /// + public static IApplicationBuilder UseRefreshTokenMiddleware(this IApplicationBuilder applicationBuilder, RefreshEndpointOptions endpointOptions = null) + { + Func defaultOnRefreshCallback = s => Task.CompletedTask; + + return applicationBuilder + .UseMiddleware(endpointOptions ?? new RefreshEndpointOptions(), defaultOnRefreshCallback, defaultOnRefreshCallback); + } + + /// + /// Registering a callback function to perform actions when when the refresh starts. + /// + /// + /// + /// + public static IRefreshMiddlewareBuilder OnRefreshExecuting(this IApplicationBuilder applicationBuilder, Func callback) + { + return RefreshMiddlewareBuilder + .GetInstance() + .SetAppBuilder(applicationBuilder) + .OnRefreshExecuting(callback); + } + + /// + /// Registering a callback function to perform actions when the refresh ends. + /// + /// + /// + /// + public static IRefreshMiddlewareBuilder OnRefreshExecuted(this IApplicationBuilder applicationBuilder, Func callback) + { + return RefreshMiddlewareBuilder + .GetInstance() + .SetAppBuilder(applicationBuilder) + .OnRefreshExecuted(callback); + } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Consts.cs b/JwtAuthentication.Shared/Consts.cs new file mode 100644 index 0000000..e795a61 --- /dev/null +++ b/JwtAuthentication.Shared/Consts.cs @@ -0,0 +1,7 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared +{ + public static class Consts + { + public const string TokenTypeClaimName = "tokenType"; + } +} diff --git a/JwtAuthentication.Shared/Exceptions/InvalidJwtTokenException.cs b/JwtAuthentication.Shared/Exceptions/InvalidJwtTokenException.cs new file mode 100644 index 0000000..7d2622a --- /dev/null +++ b/JwtAuthentication.Shared/Exceptions/InvalidJwtTokenException.cs @@ -0,0 +1,9 @@ +using System; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Errors +{ + public class InvalidJwtTokenException : Exception + { + public InvalidJwtTokenException() : base("Invalid jwt token") { } + } +} diff --git a/JwtAuthentication.Shared/JwtAuthentication.Shared.csproj b/JwtAuthentication.Shared/JwtAuthentication.Shared.csproj new file mode 100644 index 0000000..b6d363c --- /dev/null +++ b/JwtAuthentication.Shared/JwtAuthentication.Shared.csproj @@ -0,0 +1,22 @@ + + + + netcoreapp3.1;net5.0;net6.0 + TourmalineCore.AspNetCore.JwtAuthentication.Shared + + + + + + + + + + + + + + + + diff --git a/JwtAuthentication.Shared/Middlewares/Refresh/IRefreshMiddlewareBuilder.cs b/JwtAuthentication.Shared/Middlewares/Refresh/IRefreshMiddlewareBuilder.cs new file mode 100644 index 0000000..d4fff0c --- /dev/null +++ b/JwtAuthentication.Shared/Middlewares/Refresh/IRefreshMiddlewareBuilder.cs @@ -0,0 +1,17 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh +{ + public interface IRefreshMiddlewareBuilder + { + public IRefreshMiddlewareBuilder OnRefreshExecuting(Func callback); + + public IRefreshMiddlewareBuilder OnRefreshExecuted(Func callback); + + public IApplicationBuilder UseRefreshMiddleware(RefreshEndpointOptions refreshEndpointOptions = null); + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Middlewares/Refresh/Models/RefreshModel.cs b/JwtAuthentication.Shared/Middlewares/Refresh/Models/RefreshModel.cs new file mode 100644 index 0000000..6bac81a --- /dev/null +++ b/JwtAuthentication.Shared/Middlewares/Refresh/Models/RefreshModel.cs @@ -0,0 +1,7 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh.Models +{ + public class RefreshModel + { + public string RefreshTokenValue { get; set; } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddleware.cs b/JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddleware.cs new file mode 100644 index 0000000..918b994 --- /dev/null +++ b/JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddleware.cs @@ -0,0 +1,68 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh +{ + internal class RefreshMiddleware : RequestMiddlewareBase + { + private readonly RefreshEndpointOptions _endpointOptions; + private readonly ILogger _logger; + + private readonly Func _onRefreshExecuting; + private readonly Func _onRefreshExecuted; + + public RefreshMiddleware( + RequestDelegate next, + RefreshEndpointOptions endpointOptions, + ILogger logger, + Func onRefreshExecuting, + Func onRefreshExecuted) + : base(next) + { + _endpointOptions = endpointOptions; + _logger = logger; + _onRefreshExecuting = onRefreshExecuting; + _onRefreshExecuted = onRefreshExecuted; + } + + public async Task InvokeAsync(HttpContext context, ICoreRefreshService refreshService) + { + await InvokeAsyncBase(context, refreshService, _endpointOptions.RefreshEndpointRoute); + } + + protected override async Task ExecuteServiceMethod( + CoreRefreshTokenRequest requestModel, + ICoreRefreshService service, + HttpContext context) + { + var result = new TokenModel(); + + try + { + var contractRefreshModel = new RefreshModel + { + RefreshTokenValue = requestModel.RefreshTokenValue, + }; + + await _onRefreshExecuting(contractRefreshModel); + result = await service.RefreshAsync(contractRefreshModel.RefreshTokenValue); + await _onRefreshExecuted(contractRefreshModel); + } + catch (Exception ex) + { + context.Response.StatusCode = StatusCodes.Status409Conflict; + _logger.LogError(ex.ToString()); + throw new Exception(ex.Message); + } + + return result; + } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddlewareBuilder.cs b/JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddlewareBuilder.cs new file mode 100644 index 0000000..372e711 --- /dev/null +++ b/JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddlewareBuilder.cs @@ -0,0 +1,73 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh +{ + public class RefreshMiddlewareBuilder : IRefreshMiddlewareBuilder + { + private static Func _onRefreshExecutingCallback = s => Task.CompletedTask; + private static Func _onRefreshExecutedCallback = s => Task.CompletedTask; + + private IApplicationBuilder _applicationBuilder; + + private static RefreshMiddlewareBuilder _instance; + + private RefreshMiddlewareBuilder() + { + } + + internal static RefreshMiddlewareBuilder GetInstance() + { + if (_instance != null) + { + return _instance; + } + + _instance = new RefreshMiddlewareBuilder(); + + return _instance; + } + + internal IRefreshMiddlewareBuilder SetAppBuilder(IApplicationBuilder applicationBuilder) + { + _applicationBuilder = applicationBuilder; + return this; + } + + /// + /// Registering a callback function to perform actions when when the refresh starts. + /// + /// + /// + public IRefreshMiddlewareBuilder OnRefreshExecuting(Func callback) + { + _onRefreshExecutingCallback = callback; + return this; + } + + /// + /// Registering a callback function to perform actions when the refresh ends. + /// + /// + /// + public IRefreshMiddlewareBuilder OnRefreshExecuted(Func callback) + { + _onRefreshExecutedCallback = callback; + return this; + } + + /// + /// Adds middleware to handle incoming logout requests. + /// + /// + /// + public IApplicationBuilder UseRefreshMiddleware(RefreshEndpointOptions refreshEndpointOptions = null) + { + return _applicationBuilder + .UseMiddleware(refreshEndpointOptions ?? new RefreshEndpointOptions(), _onRefreshExecutingCallback, _onRefreshExecutedCallback); + } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Middlewares/RequestMiddlewareBase.cs b/JwtAuthentication.Shared/Middlewares/RequestMiddlewareBase.cs new file mode 100644 index 0000000..322759b --- /dev/null +++ b/JwtAuthentication.Shared/Middlewares/RequestMiddlewareBase.cs @@ -0,0 +1,118 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +#if NETCOREAPP3_0 || NETCOREAPP3_1 +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; + +#else +using System.Text.Json; +using System.Text.Json.Serialization; +#endif + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares +{ + internal abstract class RequestMiddlewareBase + { + private readonly RequestDelegate _next; +#if NETCOREAPP3_0 || NETCOREAPP3_1 + private readonly JsonSerializerSettings _jsonSerializerSettings; +#else + private readonly JsonSerializerOptions _jsonSerializerSettings; +#endif + protected RequestMiddlewareBase(RequestDelegate next) + { + _next = next; + +#if NETCOREAPP3_0 || NETCOREAPP3_1 + _jsonSerializerSettings = new JsonSerializerSettings + { + Formatting = Formatting.Indented, + NullValueHandling = NullValueHandling.Ignore, + Converters = + { + new IsoDateTimeConverter(), + new StringEnumConverter(), + }, + ContractResolver = new CamelCasePropertyNamesContractResolver(), + }; +#else + _jsonSerializerSettings = new JsonSerializerOptions + { + IgnoreNullValues = true, + AllowTrailingCommas = true, + WriteIndented = true, + PropertyNameCaseInsensitive = true, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + Converters = + { + new JsonStringEnumConverter(), + }, + }; +#endif + } + + protected async Task InvokeAsyncBase(HttpContext context, TService service, string endpointRoute) + { + try + { + if (context.Request.Method == HttpMethods.Post) + { + var endpoint = context.Request.Path.Value; + + if (endpoint.EndsWith(endpointRoute)) + { + var requestModel = await DeserializeModel(context.Request); + + var result = await ExecuteServiceMethod(requestModel, service, context); + + if (result != null) + { + await Response(context, result); + return; + } + } + } + } + catch (Exception ex) + { + var errorModelExample = new + { + ErrorMessage = ex.Message, + }; + + await Response(context, errorModelExample); + return; + } + + await _next(context); + } + + private async Task Response(HttpContext context, T result) + { + context.Response.ContentType = "application/json; charset=UTF-8"; +#if NETCOREAPP3_0 || NETCOREAPP3_1 + await context.Response.WriteAsync(JsonConvert.SerializeObject(result, _jsonSerializerSettings)); +#else + await context.Response.WriteAsync(JsonSerializer.Serialize(result, _jsonSerializerSettings)); +#endif + await context.Response.Body.FlushAsync(); + } + + private async Task DeserializeModel(HttpRequest request) + { + using (var reader = new StreamReader(request.Body)) + { +#if NETCOREAPP3_0 || NETCOREAPP3_1 + return JsonConvert.DeserializeObject(await reader.ReadToEndAsync(), _jsonSerializerSettings); +#else + return JsonSerializer.Deserialize(await reader.ReadToEndAsync(), _jsonSerializerSettings); +#endif + } + } + + protected abstract Task ExecuteServiceMethod(TRequestModel requestModel, TService service, HttpContext context); + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Models/Requests/CoreRefreshTokenRequest.cs b/JwtAuthentication.Shared/Models/Requests/CoreRefreshTokenRequest.cs new file mode 100644 index 0000000..a2fa578 --- /dev/null +++ b/JwtAuthentication.Shared/Models/Requests/CoreRefreshTokenRequest.cs @@ -0,0 +1,9 @@ +using System; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests +{ + public class CoreRefreshTokenRequest + { + public string RefreshTokenValue { get; set; } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Models/TokenModel.cs b/JwtAuthentication.Shared/Models/TokenModel.cs new file mode 100644 index 0000000..99383ac --- /dev/null +++ b/JwtAuthentication.Shared/Models/TokenModel.cs @@ -0,0 +1,14 @@ +using System; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("TourmalineCore.AspNetCore.JwtAuthentication.Identity")] + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models +{ + public class TokenModel + { + public string Value { get; set; } + + public DateTime ExpiresInUtc { get; set; } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Models/TokenType.cs b/JwtAuthentication.Shared/Models/TokenType.cs new file mode 100644 index 0000000..6f569c0 --- /dev/null +++ b/JwtAuthentication.Shared/Models/TokenType.cs @@ -0,0 +1,13 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models +{ + public static class TokenType + { + public const string Refresh = "refresh"; + public const string Access = "access"; + + public static bool IsAvailableTokenType(string value) + { + return value == Refresh || value == Access; + } + } +} diff --git a/JwtAuthentication.Shared/Options/AuthenticationOptions.cs b/JwtAuthentication.Shared/Options/AuthenticationOptions.cs new file mode 100644 index 0000000..d12d313 --- /dev/null +++ b/JwtAuthentication.Shared/Options/AuthenticationOptions.cs @@ -0,0 +1,23 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options +{ + public class AuthenticationOptions + { + private int _accessTokenExpireInMinutes; + + public string PublicSigningKey { get; set; } + + public string PrivateSigningKey { get; set; } + + public string Issuer { get; set; } + + public string Audience { get; set; } + + public virtual int AccessTokenExpireInMinutes + { + get => _accessTokenExpireInMinutes == default ? 10080 : _accessTokenExpireInMinutes; + set => _accessTokenExpireInMinutes = value; + } + + public bool IsDebugTokenEnabled { get; set; } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Options/RefreshEndpointOptions.cs b/JwtAuthentication.Shared/Options/RefreshEndpointOptions.cs new file mode 100644 index 0000000..633ff80 --- /dev/null +++ b/JwtAuthentication.Shared/Options/RefreshEndpointOptions.cs @@ -0,0 +1,13 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options +{ + public class RefreshEndpointOptions + { + private string _refreshEndpointRoute; + + public string RefreshEndpointRoute + { + get => _refreshEndpointRoute ?? "/auth/refresh"; + set => _refreshEndpointRoute = value; + } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Options/RefreshTokenOptions.cs b/JwtAuthentication.Shared/Options/RefreshTokenOptions.cs new file mode 100644 index 0000000..398e80a --- /dev/null +++ b/JwtAuthentication.Shared/Options/RefreshTokenOptions.cs @@ -0,0 +1,13 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options +{ + public class RefreshTokenOptions + { + private int _refreshTokenExpireInMinutes; + + public int RefreshTokenExpireInMinutes + { + get => _refreshTokenExpireInMinutes == default ? 10080 : _refreshTokenExpireInMinutes; + set => _refreshTokenExpireInMinutes = value; + } + } +} diff --git a/JwtAuthentication.Shared/Services/Contracts/ICoreRefreshService.cs b/JwtAuthentication.Shared/Services/Contracts/ICoreRefreshService.cs new file mode 100644 index 0000000..5e229f0 --- /dev/null +++ b/JwtAuthentication.Shared/Services/Contracts/ICoreRefreshService.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts +{ + public interface ICoreRefreshService + { + public Task RefreshAsync(string jwtRefreshToken); + } +} diff --git a/JwtAuthentication.Shared/Services/CoreRefreshService.cs b/JwtAuthentication.Shared/Services/CoreRefreshService.cs new file mode 100644 index 0000000..1234fa8 --- /dev/null +++ b/JwtAuthentication.Shared/Services/CoreRefreshService.cs @@ -0,0 +1,42 @@ +using System; +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Errors; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services +{ + internal class CoreRefreshService : ICoreRefreshService + { + private readonly IJwtTokenValidator _jwtTokenValidator; + private readonly IJwtTokenCreator _jwtTokenCreator; + private readonly RefreshTokenOptions _refreshTokenOptions; + + public CoreRefreshService( + IJwtTokenValidator jwtTokenValidator, + IJwtTokenCreator jwtTokenCreator, + RefreshTokenOptions refreshTokenOptions) + { + _jwtTokenValidator = jwtTokenValidator; + _jwtTokenCreator = jwtTokenCreator; + _refreshTokenOptions = refreshTokenOptions; + } + + public async Task RefreshAsync(string tokenValue) + { + try + { + await _jwtTokenValidator.ValidateTokenAsync(tokenValue); + await _jwtTokenValidator.ValidateTokenTypeAsync(tokenValue, TokenType.Refresh); + + return await _jwtTokenCreator.CreateAsync(TokenType.Refresh, _refreshTokenOptions.RefreshTokenExpireInMinutes); + } + catch (Exception) + { + throw new InvalidJwtTokenException(); + } + } + } +} diff --git a/JwtAuthentication.Shared/Signing/SigningHelper.cs b/JwtAuthentication.Shared/Signing/SigningHelper.cs new file mode 100644 index 0000000..95daf33 --- /dev/null +++ b/JwtAuthentication.Shared/Signing/SigningHelper.cs @@ -0,0 +1,29 @@ +using System; +using System.Security.Cryptography; +using Microsoft.IdentityModel.Tokens; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Signing +{ + public static class SigningHelper + { + public static RsaSecurityKey GetPublicKey(string key) + { + var publicKey = Convert.FromBase64String(key); + + var rsa = RSA.Create(); + rsa.ImportSubjectPublicKeyInfo(publicKey, out _); + + return new RsaSecurityKey(rsa); + } + + public static RsaSecurityKey GetPrivateKey(string key) + { + var privateKey = Convert.FromBase64String(key); + + var rsa = RSA.Create(); + rsa.ImportRSAPrivateKey(privateKey, out _); + + return new RsaSecurityKey(rsa); + } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenCreator.cs b/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenCreator.cs new file mode 100644 index 0000000..882e08c --- /dev/null +++ b/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenCreator.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts +{ + internal interface IJwtTokenCreator + { + Task CreateAsync(string tokenType, int tokenLifetimeInMinutes, List claims = null); + } +} diff --git a/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenValidator.cs b/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenValidator.cs new file mode 100644 index 0000000..38712d8 --- /dev/null +++ b/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenValidator.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts +{ + internal interface IJwtTokenValidator + { + Task ValidateTokenAsync(string tokenValue); + Task ValidateTokenTypeAsync(string tokenValue, string tokenType); + } +} diff --git a/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs b/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs new file mode 100644 index 0000000..8d520f1 --- /dev/null +++ b/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs @@ -0,0 +1,75 @@ +using Microsoft.IdentityModel.Tokens; +using System; +using System.Collections.Generic; +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Signing; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices +{ + internal class JwtTokenCreator : IJwtTokenCreator + { + private readonly AuthenticationOptions _authenticationOptions; + + public JwtTokenCreator(AuthenticationOptions authenticationOptions) + { + _authenticationOptions = authenticationOptions; + } + + public async Task CreateAsync(string tokenType, int tokenLifetimeInMinutes, List claims = null) + { + if (!TokenType.IsAvailableTokenType(tokenType)) + { + throw new ArgumentException("Invalid token type value"); + } + + if (tokenLifetimeInMinutes <= 0) + { + throw new ArgumentException("Token lifetime cannot be negative or zero"); + } + + if (claims == null) + { + claims = new List(); + } + + AddTokenTypeClaim(claims, tokenType); + + var tokenExpiresIn = DateTime.UtcNow.AddMinutes(tokenLifetimeInMinutes); + + var token = new JwtSecurityToken( + _authenticationOptions.Issuer, + _authenticationOptions.Audience, + claims, + expires: tokenExpiresIn, + signingCredentials: GetCredentials()); + + return await Task.FromResult(new TokenModel + { + Value = new JwtSecurityTokenHandler().WriteToken(token), + ExpiresInUtc = tokenExpiresIn.ToUniversalTime(), + }); + } + + private SigningCredentials GetCredentials() + { + var privateKey = SigningHelper.GetPrivateKey(_authenticationOptions.PrivateSigningKey); + + return new SigningCredentials(privateKey, SecurityAlgorithms.RsaSha256); + } + + private void AddTokenTypeClaim(List claims, string tokenTypeValue) + { + var isTokenTypeClaimSet = claims.Exists(x => x.Type == Consts.TokenTypeClaimName); + + if (!isTokenTypeClaimSet) + { + claims.Add(new Claim(Consts.TokenTypeClaimName, tokenTypeValue)); + } + } + } +} diff --git a/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs b/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs new file mode 100644 index 0000000..2889a8c --- /dev/null +++ b/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs @@ -0,0 +1,61 @@ +using Microsoft.IdentityModel.Tokens; +using System; +using System.IdentityModel.Tokens.Jwt; +using System.Linq; +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Signing; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices +{ + internal class JwtTokenValidator : IJwtTokenValidator + { + private readonly AuthenticationOptions _authenticationOptions; + + public JwtTokenValidator(AuthenticationOptions options) + { + _authenticationOptions = options; + } + + public Task ValidateTokenAsync(string tokenValue) + { + var handler = new JwtSecurityTokenHandler(); + var tokenValidationParameters = new TokenValidationParameters + { + ValidateLifetime = true, + ValidateIssuer = false, + ValidateAudience = false, + ValidateIssuerSigningKey = true, + IssuerSigningKey = SigningHelper.GetPublicKey(_authenticationOptions.PublicSigningKey), + ClockSkew = TimeSpan.Zero, + }; + + return Task.Run(() => handler.ValidateToken(tokenValue, tokenValidationParameters, out var _)); + } + + public Task ValidateTokenTypeAsync(string tokenValue, string tokenType) + { + if (!TokenType.IsAvailableTokenType(tokenType)) + { + throw new ArgumentException("Invalid token type value"); + } + + var token = new JwtSecurityTokenHandler().ReadJwtToken(tokenValue); + var tokenTypeClaim = token.Claims.SingleOrDefault(claim => claim.Type == Consts.TokenTypeClaimName); + + if (tokenTypeClaim == null) + { + throw new Exception("Token type claim is not set"); + } + + if (tokenTypeClaim.Value != tokenType) + { + throw new ArgumentException($"Token type is not '{tokenType}'"); + } + + return Task.CompletedTask; + } + } +} From 7d536f222a3bbd57a2ba5acd34ca2ed903fb97d5 Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Thu, 18 Aug 2022 11:32:22 +0500 Subject: [PATCH 17/34] style(editorconfig): #60: changes the end of lines --- .editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 770629e..8c6307f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,7 +9,7 @@ indent_style = space tab_width = 4 # New line preferences -end_of_line = crlf +end_of_line = lf insert_final_newline = false From 26cf4f962f628b4814f1f9b17127e58290a448c1 Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Thu, 18 Aug 2022 11:39:02 +0500 Subject: [PATCH 18/34] build(solution): #60: removes .netcore3.0 support --- AspNetCore.JwtAuthentication.sln | 9 +-------- .../Tests/{NetCore3.0 => NetCore3.1}/BasicAuthTests.cs | 6 +++--- Examples/Tests/Tests.csproj | 2 +- JwtAuthentication.Core/JwtAuthentication.Core.csproj | 2 +- .../JwtAuthentication.Identity.csproj | 2 +- 5 files changed, 7 insertions(+), 14 deletions(-) rename Examples/Tests/{NetCore3.0 => NetCore3.1}/BasicAuthTests.cs (91%) diff --git a/AspNetCore.JwtAuthentication.sln b/AspNetCore.JwtAuthentication.sln index 120834c..e79aa7d 100644 --- a/AspNetCore.JwtAuthentication.sln +++ b/AspNetCore.JwtAuthentication.sln @@ -18,8 +18,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore5.0.Permissi EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore5.0.WithCredentialsValidator", "Examples\Example.NetCore5.0.WithCredentialsValidator\Example.NetCore5.0.WithCredentialsValidator.csproj", "{E2BC2C97-161E-41E4-B224-DFC62AD56768}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore3.0.BaseAuthentication", "Examples\Example.NetCore3.0.BaseAuthentication\Example.NetCore3.0.BaseAuthentication.csproj", "{6AB1E6C4-563A-4447-8024-6C31C9A45141}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore3.1.BaseAuthentication", "Examples\Example.NetCore3.1.BaseAuthentication\Example.NetCore3.1.BaseAuthentication.csproj", "{43D3813D-CD36-46A7-86EF-CD6CF0A9A9BC}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore5.0.CookiesBasedAuthentication", "Examples\Example.NetCore5.0.CookiesBasedAuthentication\Example.NetCore5.0.CookiesBasedAuthentication.csproj", "{32E74378-AAF5-4CA6-8633-30997453E58A}" @@ -62,7 +60,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore5.0.RefreshT EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore3.1.AuthenticationWithRefreshToken", "Examples\Example.NetCore3.1.AuthenticationWithRefreshToken\Example.NetCore3.1.AuthenticationWithRefreshToken.csproj", "{63E8464D-8489-4423-ADCD-1107DC5D9336}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JwtAuthentication.Shared", "JwtAuthentication.Shared\JwtAuthentication.Shared.csproj", "{E1952561-A7CD-45C3-B9D0-AC9B92A194CC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JwtAuthentication.Shared", "JwtAuthentication.Shared\JwtAuthentication.Shared.csproj", "{E1952561-A7CD-45C3-B9D0-AC9B92A194CC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -86,10 +84,6 @@ Global {E2BC2C97-161E-41E4-B224-DFC62AD56768}.Debug|Any CPU.Build.0 = Debug|Any CPU {E2BC2C97-161E-41E4-B224-DFC62AD56768}.Release|Any CPU.ActiveCfg = Release|Any CPU {E2BC2C97-161E-41E4-B224-DFC62AD56768}.Release|Any CPU.Build.0 = Release|Any CPU - {6AB1E6C4-563A-4447-8024-6C31C9A45141}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6AB1E6C4-563A-4447-8024-6C31C9A45141}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6AB1E6C4-563A-4447-8024-6C31C9A45141}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6AB1E6C4-563A-4447-8024-6C31C9A45141}.Release|Any CPU.Build.0 = Release|Any CPU {43D3813D-CD36-46A7-86EF-CD6CF0A9A9BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {43D3813D-CD36-46A7-86EF-CD6CF0A9A9BC}.Debug|Any CPU.Build.0 = Debug|Any CPU {43D3813D-CD36-46A7-86EF-CD6CF0A9A9BC}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -174,7 +168,6 @@ Global {36F676C3-2C5F-4727-8BE2-8F759C2A3FBE} = {7A925031-2656-4CEB-821A-D76739E0E5A2} {51E0C282-0942-4367-95EB-F248E80A5D6F} = {7A925031-2656-4CEB-821A-D76739E0E5A2} {E2BC2C97-161E-41E4-B224-DFC62AD56768} = {7A925031-2656-4CEB-821A-D76739E0E5A2} - {6AB1E6C4-563A-4447-8024-6C31C9A45141} = {614DB4C6-A4BE-4BBF-B385-C34985CA1FC3} {43D3813D-CD36-46A7-86EF-CD6CF0A9A9BC} = {614DB4C6-A4BE-4BBF-B385-C34985CA1FC3} {32E74378-AAF5-4CA6-8633-30997453E58A} = {7A925031-2656-4CEB-821A-D76739E0E5A2} {1DF1D001-0194-4CD8-82DD-40AF57FC1432} = {7A925031-2656-4CEB-821A-D76739E0E5A2} diff --git a/Examples/Tests/NetCore3.0/BasicAuthTests.cs b/Examples/Tests/NetCore3.1/BasicAuthTests.cs similarity index 91% rename from Examples/Tests/NetCore3.0/BasicAuthTests.cs rename to Examples/Tests/NetCore3.1/BasicAuthTests.cs index e3b32b2..da6e877 100644 --- a/Examples/Tests/NetCore3.0/BasicAuthTests.cs +++ b/Examples/Tests/NetCore3.1/BasicAuthTests.cs @@ -1,11 +1,11 @@ using System.Net; -using Example.NetCore3._0.BaseAuthentication; +using Example.NetCore3._1.BaseAuthentication; using Microsoft.AspNetCore.Mvc.Testing; using Xunit; -namespace Tests.NetCore3._0 +namespace Tests.NetCore3._1 { - [Collection(nameof(Example.NetCore3._0.BaseAuthentication))] + [Collection(nameof(Example.NetCore3._1.BaseAuthentication))] public class BasicAuthTests : AuthTestsBase { diff --git a/Examples/Tests/Tests.csproj b/Examples/Tests/Tests.csproj index 20a18c5..b78e21e 100644 --- a/Examples/Tests/Tests.csproj +++ b/Examples/Tests/Tests.csproj @@ -24,7 +24,7 @@ - + diff --git a/JwtAuthentication.Core/JwtAuthentication.Core.csproj b/JwtAuthentication.Core/JwtAuthentication.Core.csproj index 058af84..3ccbf58 100644 --- a/JwtAuthentication.Core/JwtAuthentication.Core.csproj +++ b/JwtAuthentication.Core/JwtAuthentication.Core.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;netcoreapp3.1;net5.0;net6.0 + netcoreapp3.1;net5.0;net6.0 TourmalineCore.AspNetCore.JwtAuthentication.Core 0.3.4-alpha.2 Koval Maxim, Nikita Medvedev, Aleksandr Shinkarev diff --git a/JwtAuthentication.Identity/JwtAuthentication.Identity.csproj b/JwtAuthentication.Identity/JwtAuthentication.Identity.csproj index d3d68c6..945e9f1 100644 --- a/JwtAuthentication.Identity/JwtAuthentication.Identity.csproj +++ b/JwtAuthentication.Identity/JwtAuthentication.Identity.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;netcoreapp3.1;net5.0;net6.0 + netcoreapp3.1;net5.0;net6.0 TourmalineCore.AspNetCore.JwtAuthentication.Identity 0.1.0-alpha.2 Koval Maxim, Nikita Medvedev From f6358d3abade5ab3d371ae1aa81daeff2a0f080b Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Thu, 18 Aug 2022 11:40:03 +0500 Subject: [PATCH 19/34] build(examles): #60: removes the .netcore3.0 example --- .../Controllers/ExampleController.cs | 32 -------------- ...ample.NetCore3.0.BaseAuthentication.csproj | 20 --------- .../Program.cs | 19 -------- .../Properties/launchSettings.json | 27 ------------ .../Startup.cs | 43 ------------------- .../appsettings.json | 6 --- 6 files changed, 147 deletions(-) delete mode 100644 Examples/Example.NetCore3.0.BaseAuthentication/Controllers/ExampleController.cs delete mode 100644 Examples/Example.NetCore3.0.BaseAuthentication/Example.NetCore3.0.BaseAuthentication.csproj delete mode 100644 Examples/Example.NetCore3.0.BaseAuthentication/Program.cs delete mode 100644 Examples/Example.NetCore3.0.BaseAuthentication/Properties/launchSettings.json delete mode 100644 Examples/Example.NetCore3.0.BaseAuthentication/Startup.cs delete mode 100644 Examples/Example.NetCore3.0.BaseAuthentication/appsettings.json diff --git a/Examples/Example.NetCore3.0.BaseAuthentication/Controllers/ExampleController.cs b/Examples/Example.NetCore3.0.BaseAuthentication/Controllers/ExampleController.cs deleted file mode 100644 index 3f6181a..0000000 --- a/Examples/Example.NetCore3.0.BaseAuthentication/Controllers/ExampleController.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Collections.Generic; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; - -namespace Example.NetCore3._0.BaseAuthentication.Controllers -{ - [ApiController] - [Route("[controller]")] - public class ExampleController : ControllerBase - { - private static readonly string[] Summaries = - { - "Freezing", - "Bracing", - "Chilly", - "Cool", - "Mild", - "Warm", - "Balmy", - "Hot", - "Sweltering", - "Scorching", - }; - - [Authorize] - [HttpGet] - public IEnumerable Get() - { - return Summaries; - } - } -} \ No newline at end of file diff --git a/Examples/Example.NetCore3.0.BaseAuthentication/Example.NetCore3.0.BaseAuthentication.csproj b/Examples/Example.NetCore3.0.BaseAuthentication/Example.NetCore3.0.BaseAuthentication.csproj deleted file mode 100644 index 4f46280..0000000 --- a/Examples/Example.NetCore3.0.BaseAuthentication/Example.NetCore3.0.BaseAuthentication.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - netcoreapp3.0 - Example.NetCore3._0.BaseAuthentication - - - - - - - - - PreserveNewest - true - PreserveNewest - - - - diff --git a/Examples/Example.NetCore3.0.BaseAuthentication/Program.cs b/Examples/Example.NetCore3.0.BaseAuthentication/Program.cs deleted file mode 100644 index a9c46c4..0000000 --- a/Examples/Example.NetCore3.0.BaseAuthentication/Program.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Hosting; - -namespace Example.NetCore3._0.BaseAuthentication -{ - public class Program - { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } - - public static IHostBuilder CreateHostBuilder(string[] args) - { - return Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); - } - } -} \ No newline at end of file diff --git a/Examples/Example.NetCore3.0.BaseAuthentication/Properties/launchSettings.json b/Examples/Example.NetCore3.0.BaseAuthentication/Properties/launchSettings.json deleted file mode 100644 index 20acd9c..0000000 --- a/Examples/Example.NetCore3.0.BaseAuthentication/Properties/launchSettings.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:55870/", - "sslPort": 44324 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "Example.NetCore3._0.BaseAuthentication": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "http://localhost:5000" - } - } -} \ No newline at end of file diff --git a/Examples/Example.NetCore3.0.BaseAuthentication/Startup.cs b/Examples/Example.NetCore3.0.BaseAuthentication/Startup.cs deleted file mode 100644 index 810e4fa..0000000 --- a/Examples/Example.NetCore3.0.BaseAuthentication/Startup.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using TourmalineCore.AspNetCore.JwtAuthentication.Core; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; - -namespace Example.NetCore3._0.BaseAuthentication -{ - public class Startup - { - private readonly IConfiguration _configuration; - - public Startup(IConfiguration configuration) - { - _configuration = configuration; - } - - public void ConfigureServices(IServiceCollection services) - { - services.AddJwtAuthentication(_configuration.GetSection(nameof(AuthenticationOptions)).Get()); - - services.AddControllers(); - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseRouting(); - - app - .UseDefaultLoginMiddleware() - .UseJwtAuthentication(); - - app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); - } - } -} \ No newline at end of file diff --git a/Examples/Example.NetCore3.0.BaseAuthentication/appsettings.json b/Examples/Example.NetCore3.0.BaseAuthentication/appsettings.json deleted file mode 100644 index dc634db..0000000 --- a/Examples/Example.NetCore3.0.BaseAuthentication/appsettings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "AuthenticationOptions": { - "PublicSigningKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQAB", - "PrivateSigningKey": "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU" - } -} \ No newline at end of file From 14508adf5b8925d13b2211adf7b964c62570aac2 Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Mon, 22 Aug 2022 16:48:20 +0500 Subject: [PATCH 20/34] chore(shared): #60: sets public modifier for all files in the shared project --- .../Exceptions/IncorrectLoginOrPasswordException.cs | 9 +++++++++ .../RefreshTokenIsNotInConfidenceIntervalException.cs | 9 +++++++++ .../Exceptions/RefreshTokenNotFoundException.cs | 9 +++++++++ .../RefreshTokenOrFingerprintNotFoundException.cs | 9 +++++++++ .../Exceptions/RegistrationException.cs | 9 +++++++++ .../Middlewares/Refresh/RefreshMiddleware.cs | 2 +- .../Middlewares/RequestMiddlewareBase.cs | 2 +- .../Models/Requests/CoreRefreshTokenRequest.cs | 2 -- JwtAuthentication.Shared/Models/TokenModel.cs | 3 --- JwtAuthentication.Shared/Services/CoreRefreshService.cs | 2 +- .../TokenServices/Contracts/IJwtTokenCreator.cs | 2 +- .../TokenServices/Contracts/IJwtTokenValidator.cs | 2 +- .../TokenServices/JwtTokenCreator.cs | 2 +- .../TokenServices/JwtTokenValidator.cs | 2 +- 14 files changed, 52 insertions(+), 12 deletions(-) create mode 100644 JwtAuthentication.Shared/Exceptions/IncorrectLoginOrPasswordException.cs create mode 100644 JwtAuthentication.Shared/Exceptions/RefreshTokenIsNotInConfidenceIntervalException.cs create mode 100644 JwtAuthentication.Shared/Exceptions/RefreshTokenNotFoundException.cs create mode 100644 JwtAuthentication.Shared/Exceptions/RefreshTokenOrFingerprintNotFoundException.cs create mode 100644 JwtAuthentication.Shared/Exceptions/RegistrationException.cs diff --git a/JwtAuthentication.Shared/Exceptions/IncorrectLoginOrPasswordException.cs b/JwtAuthentication.Shared/Exceptions/IncorrectLoginOrPasswordException.cs new file mode 100644 index 0000000..3d560f1 --- /dev/null +++ b/JwtAuthentication.Shared/Exceptions/IncorrectLoginOrPasswordException.cs @@ -0,0 +1,9 @@ +using System; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Errors +{ + public class IncorrectLoginOrPasswordException : Exception + { + public IncorrectLoginOrPasswordException() : base("Incorrect login or password") { } + } +} diff --git a/JwtAuthentication.Shared/Exceptions/RefreshTokenIsNotInConfidenceIntervalException.cs b/JwtAuthentication.Shared/Exceptions/RefreshTokenIsNotInConfidenceIntervalException.cs new file mode 100644 index 0000000..b6734c9 --- /dev/null +++ b/JwtAuthentication.Shared/Exceptions/RefreshTokenIsNotInConfidenceIntervalException.cs @@ -0,0 +1,9 @@ +using System; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Errors +{ + public class RefreshTokenIsNotInConfidenceIntervalException : Exception + { + public RefreshTokenIsNotInConfidenceIntervalException() : base("Refresh token is not in confidence interval") { } + } +} diff --git a/JwtAuthentication.Shared/Exceptions/RefreshTokenNotFoundException.cs b/JwtAuthentication.Shared/Exceptions/RefreshTokenNotFoundException.cs new file mode 100644 index 0000000..db6c979 --- /dev/null +++ b/JwtAuthentication.Shared/Exceptions/RefreshTokenNotFoundException.cs @@ -0,0 +1,9 @@ +using System; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Errors +{ + public class RefreshTokenNotFoundException : Exception + { + public RefreshTokenNotFoundException() : base("Refresh token not found") { } + } +} diff --git a/JwtAuthentication.Shared/Exceptions/RefreshTokenOrFingerprintNotFoundException.cs b/JwtAuthentication.Shared/Exceptions/RefreshTokenOrFingerprintNotFoundException.cs new file mode 100644 index 0000000..8a95bb0 --- /dev/null +++ b/JwtAuthentication.Shared/Exceptions/RefreshTokenOrFingerprintNotFoundException.cs @@ -0,0 +1,9 @@ +using System; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Errors +{ + public class RefreshTokenOrFingerprintNotFoundException : Exception + { + public RefreshTokenOrFingerprintNotFoundException() : base("Refresh token or fingerprint not found") { } + } +} diff --git a/JwtAuthentication.Shared/Exceptions/RegistrationException.cs b/JwtAuthentication.Shared/Exceptions/RegistrationException.cs new file mode 100644 index 0000000..85748ea --- /dev/null +++ b/JwtAuthentication.Shared/Exceptions/RegistrationException.cs @@ -0,0 +1,9 @@ +using System; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Errors +{ + public class RegistrationException : Exception + { + public RegistrationException() : base("An registration exception occured") { } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddleware.cs b/JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddleware.cs index 918b994..4c1567d 100644 --- a/JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddleware.cs +++ b/JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddleware.cs @@ -10,7 +10,7 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh { - internal class RefreshMiddleware : RequestMiddlewareBase + public class RefreshMiddleware : RequestMiddlewareBase { private readonly RefreshEndpointOptions _endpointOptions; private readonly ILogger _logger; diff --git a/JwtAuthentication.Shared/Middlewares/RequestMiddlewareBase.cs b/JwtAuthentication.Shared/Middlewares/RequestMiddlewareBase.cs index 322759b..d7e8370 100644 --- a/JwtAuthentication.Shared/Middlewares/RequestMiddlewareBase.cs +++ b/JwtAuthentication.Shared/Middlewares/RequestMiddlewareBase.cs @@ -14,7 +14,7 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares { - internal abstract class RequestMiddlewareBase + public abstract class RequestMiddlewareBase { private readonly RequestDelegate _next; #if NETCOREAPP3_0 || NETCOREAPP3_1 diff --git a/JwtAuthentication.Shared/Models/Requests/CoreRefreshTokenRequest.cs b/JwtAuthentication.Shared/Models/Requests/CoreRefreshTokenRequest.cs index a2fa578..3e3dae9 100644 --- a/JwtAuthentication.Shared/Models/Requests/CoreRefreshTokenRequest.cs +++ b/JwtAuthentication.Shared/Models/Requests/CoreRefreshTokenRequest.cs @@ -1,5 +1,3 @@ -using System; - namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests { public class CoreRefreshTokenRequest diff --git a/JwtAuthentication.Shared/Models/TokenModel.cs b/JwtAuthentication.Shared/Models/TokenModel.cs index 99383ac..ffb5302 100644 --- a/JwtAuthentication.Shared/Models/TokenModel.cs +++ b/JwtAuthentication.Shared/Models/TokenModel.cs @@ -1,7 +1,4 @@ using System; -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("TourmalineCore.AspNetCore.JwtAuthentication.Identity")] namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models { diff --git a/JwtAuthentication.Shared/Services/CoreRefreshService.cs b/JwtAuthentication.Shared/Services/CoreRefreshService.cs index 1234fa8..e1da234 100644 --- a/JwtAuthentication.Shared/Services/CoreRefreshService.cs +++ b/JwtAuthentication.Shared/Services/CoreRefreshService.cs @@ -8,7 +8,7 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services { - internal class CoreRefreshService : ICoreRefreshService + public class CoreRefreshService : ICoreRefreshService { private readonly IJwtTokenValidator _jwtTokenValidator; private readonly IJwtTokenCreator _jwtTokenCreator; diff --git a/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenCreator.cs b/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenCreator.cs index 882e08c..19a55a8 100644 --- a/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenCreator.cs +++ b/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenCreator.cs @@ -5,7 +5,7 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts { - internal interface IJwtTokenCreator + public interface IJwtTokenCreator { Task CreateAsync(string tokenType, int tokenLifetimeInMinutes, List claims = null); } diff --git a/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenValidator.cs b/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenValidator.cs index 38712d8..5fb3175 100644 --- a/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenValidator.cs +++ b/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenValidator.cs @@ -2,7 +2,7 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts { - internal interface IJwtTokenValidator + public interface IJwtTokenValidator { Task ValidateTokenAsync(string tokenValue); Task ValidateTokenTypeAsync(string tokenValue, string tokenType); diff --git a/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs b/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs index 8d520f1..7bd012a 100644 --- a/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs +++ b/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs @@ -11,7 +11,7 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices { - internal class JwtTokenCreator : IJwtTokenCreator + public class JwtTokenCreator : IJwtTokenCreator { private readonly AuthenticationOptions _authenticationOptions; diff --git a/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs b/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs index 2889a8c..5ac21ea 100644 --- a/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs +++ b/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs @@ -10,7 +10,7 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices { - internal class JwtTokenValidator : IJwtTokenValidator + public class JwtTokenValidator : IJwtTokenValidator { private readonly AuthenticationOptions _authenticationOptions; From 921859769632b18f662496a502a5df1e4e89d469 Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Mon, 22 Aug 2022 18:20:34 +0500 Subject: [PATCH 21/34] chore: #60: starts to split core and shared projects --- Examples/Tests/Units/JwtTokenCreatorTests.cs | 9 ++- .../Tests/Units/JwtTokenValidatorTests.cs | 4 +- .../AuthenticationExtensions.cs | 4 +- .../Contract/IJwtTokenCreator.cs | 12 --- .../Contract/IJwtTokenValidator.cs | 10 --- .../Contract/JwtTokenCreator.cs | 74 ------------------- .../Contract/JwtTokenValidator.cs | 59 --------------- JwtAuthentication.Core/Contract/TokenType.cs | 13 ---- .../JwtAuthentication.Core.csproj | 4 + .../Middlewares/Refresh/RefreshMiddleware.cs | 14 ++-- .../Models/Response/AuthResponseModel.cs | 1 + JwtAuthentication.Core/Models/TokenModel.cs | 14 ---- .../Services/ICoreRefreshService.cs | 4 +- .../Services/ICoreRefreshTokenManager.cs | 4 +- .../Services/IRefreshTokenManager.cs | 2 +- .../Services/ITokenManager.cs | 2 +- .../Implementation/CoreRefreshTokenManager.cs | 6 +- .../Services/Implementation/RefreshService.cs | 6 +- .../Services/Implementation/TokenManager.cs | 24 +++--- .../Signing/SigningHelper.cs | 29 -------- .../Services/IdentityLoginService.cs | 1 + .../Services/RefreshTokenManager.cs | 4 +- ...ions.cs => SharedAuthenticationOptions.cs} | 2 +- .../TokenServices/JwtTokenCreator.cs | 4 +- .../TokenServices/JwtTokenValidator.cs | 4 +- 25 files changed, 55 insertions(+), 255 deletions(-) delete mode 100644 JwtAuthentication.Core/Contract/IJwtTokenCreator.cs delete mode 100644 JwtAuthentication.Core/Contract/IJwtTokenValidator.cs delete mode 100644 JwtAuthentication.Core/Contract/JwtTokenCreator.cs delete mode 100644 JwtAuthentication.Core/Contract/JwtTokenValidator.cs delete mode 100644 JwtAuthentication.Core/Contract/TokenType.cs delete mode 100644 JwtAuthentication.Core/Models/TokenModel.cs delete mode 100644 JwtAuthentication.Core/Signing/SigningHelper.cs rename JwtAuthentication.Shared/Options/{AuthenticationOptions.cs => SharedAuthenticationOptions.cs} (93%) diff --git a/Examples/Tests/Units/JwtTokenCreatorTests.cs b/Examples/Tests/Units/JwtTokenCreatorTests.cs index 3c63ba6..45c1f30 100644 --- a/Examples/Tests/Units/JwtTokenCreatorTests.cs +++ b/Examples/Tests/Units/JwtTokenCreatorTests.cs @@ -1,9 +1,10 @@ using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using TourmalineCore.AspNetCore.JwtAuthentication.Core; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; using Xunit; namespace Tests.Units; @@ -15,7 +16,7 @@ public class JwtTokenCreatorTests public JwtTokenCreatorTests() { - var authenticationOptions = new AuthenticationOptions() + var authenticationOptions = new SharedAuthenticationOptions() { PrivateSigningKey = "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU", }; diff --git a/Examples/Tests/Units/JwtTokenValidatorTests.cs b/Examples/Tests/Units/JwtTokenValidatorTests.cs index 44cfdd9..84bc9b6 100644 --- a/Examples/Tests/Units/JwtTokenValidatorTests.cs +++ b/Examples/Tests/Units/JwtTokenValidatorTests.cs @@ -1,5 +1,7 @@ using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices; using Xunit; namespace Tests.Units; @@ -14,7 +16,7 @@ public class JwtTokenValidatorTests public JwtTokenValidatorTests() { - var authenticationOptions = new AuthenticationOptions() + var authenticationOptions = new SharedAuthenticationOptions() { PublicSigningKey = PublicSigningKey }; diff --git a/JwtAuthentication.Core/AuthenticationExtensions.cs b/JwtAuthentication.Core/AuthenticationExtensions.cs index 2132f0b..4360356 100644 --- a/JwtAuthentication.Core/AuthenticationExtensions.cs +++ b/JwtAuthentication.Core/AuthenticationExtensions.cs @@ -11,8 +11,10 @@ using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Signing; using TourmalineCore.AspNetCore.JwtAuthentication.Core.TokenHandlers; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Signing; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; using AuthenticationOptions = TourmalineCore.AspNetCore.JwtAuthentication.Core.Options.AuthenticationOptions; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core diff --git a/JwtAuthentication.Core/Contract/IJwtTokenCreator.cs b/JwtAuthentication.Core/Contract/IJwtTokenCreator.cs deleted file mode 100644 index 5f74ea6..0000000 --- a/JwtAuthentication.Core/Contract/IJwtTokenCreator.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System.Collections.Generic; -using System.Security.Claims; -using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract -{ - internal interface IJwtTokenCreator - { - Task CreateAsync(string tokenType, int tokenLifetimeInMinutes, List claims = null); - } -} diff --git a/JwtAuthentication.Core/Contract/IJwtTokenValidator.cs b/JwtAuthentication.Core/Contract/IJwtTokenValidator.cs deleted file mode 100644 index 7183e55..0000000 --- a/JwtAuthentication.Core/Contract/IJwtTokenValidator.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Threading.Tasks; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract -{ - internal interface IJwtTokenValidator - { - Task ValidateTokenAsync(string tokenValue); - Task ValidateTokenTypeAsync(string tokenValue, string tokenType); - } -} diff --git a/JwtAuthentication.Core/Contract/JwtTokenCreator.cs b/JwtAuthentication.Core/Contract/JwtTokenCreator.cs deleted file mode 100644 index f174288..0000000 --- a/JwtAuthentication.Core/Contract/JwtTokenCreator.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Microsoft.IdentityModel.Tokens; -using System; -using System.Collections.Generic; -using System.IdentityModel.Tokens.Jwt; -using System.Security.Claims; -using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Signing; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract -{ - internal class JwtTokenCreator : IJwtTokenCreator - { - private readonly AuthenticationOptions _authenticationOptions; - - public JwtTokenCreator(AuthenticationOptions authenticationOptions) - { - _authenticationOptions = authenticationOptions; - } - - public async Task CreateAsync(string tokenType, int tokenLifetimeInMinutes, List claims = null) - { - if (!TokenType.IsAvailableTokenType(tokenType)) - { - throw new ArgumentException("Invalid token type value"); - } - - if (tokenLifetimeInMinutes <= 0) - { - throw new ArgumentException("Token lifetime cannot be negative or zero"); - } - - if (claims == null) - { - claims = new List(); - } - - AddTokenTypeClaim(claims, tokenType); - - var tokenExpiresIn = DateTime.UtcNow.AddMinutes(tokenLifetimeInMinutes); - - var token = new JwtSecurityToken( - _authenticationOptions.Issuer, - _authenticationOptions.Audience, - claims, - expires: tokenExpiresIn, - signingCredentials: GetCredentials()); - - return await Task.FromResult(new TokenModel - { - Value = new JwtSecurityTokenHandler().WriteToken(token), - ExpiresInUtc = tokenExpiresIn.ToUniversalTime(), - }); - } - - private SigningCredentials GetCredentials() - { - var privateKey = SigningHelper.GetPrivateKey(_authenticationOptions.PrivateSigningKey); - - return new SigningCredentials(privateKey, SecurityAlgorithms.RsaSha256); - } - - private void AddTokenTypeClaim(List claims, string tokenTypeValue) - { - var isTokenTypeClaimSet = claims.Exists(x => x.Type == Consts.TokenTypeClaimName); - - if (!isTokenTypeClaimSet) - { - claims.Add(new Claim(Consts.TokenTypeClaimName, tokenTypeValue)); - } - } - } -} diff --git a/JwtAuthentication.Core/Contract/JwtTokenValidator.cs b/JwtAuthentication.Core/Contract/JwtTokenValidator.cs deleted file mode 100644 index 9c956da..0000000 --- a/JwtAuthentication.Core/Contract/JwtTokenValidator.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Microsoft.IdentityModel.Tokens; -using System; -using System.IdentityModel.Tokens.Jwt; -using System.Linq; -using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Signing; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract -{ - internal class JwtTokenValidator : IJwtTokenValidator - { - private readonly AuthenticationOptions _authenticationOptions; - - public JwtTokenValidator(AuthenticationOptions options) - { - _authenticationOptions = options; - } - - public Task ValidateTokenAsync(string tokenValue) - { - var handler = new JwtSecurityTokenHandler(); - var tokenValidationParameters = new TokenValidationParameters - { - ValidateLifetime = true, - ValidateIssuer = false, - ValidateAudience = false, - ValidateIssuerSigningKey = true, - IssuerSigningKey = SigningHelper.GetPublicKey(_authenticationOptions.PublicSigningKey), - ClockSkew = TimeSpan.Zero, - }; - - return Task.Run(() => handler.ValidateToken(tokenValue, tokenValidationParameters, out var _)); - } - - public Task ValidateTokenTypeAsync(string tokenValue, string tokenType) - { - if (!TokenType.IsAvailableTokenType(tokenType)) - { - throw new ArgumentException("Invalid token type value"); - } - - var token = new JwtSecurityTokenHandler().ReadJwtToken(tokenValue); - var tokenTypeClaim = token.Claims.SingleOrDefault(claim => claim.Type == Consts.TokenTypeClaimName); - - if (tokenTypeClaim == null) - { - throw new Exception("Token type claim is not set"); - } - - if (tokenTypeClaim.Value != tokenType) - { - throw new ArgumentException($"Token type is not '{tokenType}'"); - } - - return Task.CompletedTask; - } - } -} diff --git a/JwtAuthentication.Core/Contract/TokenType.cs b/JwtAuthentication.Core/Contract/TokenType.cs deleted file mode 100644 index 6b76b3c..0000000 --- a/JwtAuthentication.Core/Contract/TokenType.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract -{ - public static class TokenType - { - public const string Refresh = "refresh"; - public const string Access = "access"; - - public static bool IsAvailableTokenType(string value) - { - return value == Refresh || value == Access; - } - } -} diff --git a/JwtAuthentication.Core/JwtAuthentication.Core.csproj b/JwtAuthentication.Core/JwtAuthentication.Core.csproj index 3ccbf58..fd3ab6f 100644 --- a/JwtAuthentication.Core/JwtAuthentication.Core.csproj +++ b/JwtAuthentication.Core/JwtAuthentication.Core.csproj @@ -48,4 +48,8 @@ + + + + diff --git a/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs b/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs index 82931d4..41aeb6d 100644 --- a/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs +++ b/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs @@ -1,12 +1,12 @@ -using System; +using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh { @@ -56,9 +56,9 @@ protected override async Task ExecuteServiceMethod( await _onRefreshExecuted(contractRefreshModel); } catch (Exception ex) - { - context.Response.StatusCode = StatusCodes.Status409Conflict; - _logger.LogError(ex.ToString()); + { + context.Response.StatusCode = StatusCodes.Status409Conflict; + _logger.LogError(ex.ToString()); throw new Exception(ex.Message); } diff --git a/JwtAuthentication.Core/Models/Response/AuthResponseModel.cs b/JwtAuthentication.Core/Models/Response/AuthResponseModel.cs index bf1599e..9072485 100644 --- a/JwtAuthentication.Core/Models/Response/AuthResponseModel.cs +++ b/JwtAuthentication.Core/Models/Response/AuthResponseModel.cs @@ -1,4 +1,5 @@ using System.Runtime.CompilerServices; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; [assembly: InternalsVisibleTo("TourmalineCore.AspNetCore.JwtAuthentication.Identity")] [assembly: InternalsVisibleTo("Tests")] diff --git a/JwtAuthentication.Core/Models/TokenModel.cs b/JwtAuthentication.Core/Models/TokenModel.cs deleted file mode 100644 index 42b132c..0000000 --- a/JwtAuthentication.Core/Models/TokenModel.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("TourmalineCore.AspNetCore.JwtAuthentication.Identity")] - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Models -{ - internal class TokenModel - { - public string Value { get; set; } - - public DateTime ExpiresInUtc { get; set; } - } -} \ No newline at end of file diff --git a/JwtAuthentication.Core/Services/ICoreRefreshService.cs b/JwtAuthentication.Core/Services/ICoreRefreshService.cs index 9346ffe..75d60d2 100644 --- a/JwtAuthentication.Core/Services/ICoreRefreshService.cs +++ b/JwtAuthentication.Core/Services/ICoreRefreshService.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; - +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services { internal interface ICoreRefreshService diff --git a/JwtAuthentication.Core/Services/ICoreRefreshTokenManager.cs b/JwtAuthentication.Core/Services/ICoreRefreshTokenManager.cs index d1fedb5..57168d7 100644 --- a/JwtAuthentication.Core/Services/ICoreRefreshTokenManager.cs +++ b/JwtAuthentication.Core/Services/ICoreRefreshTokenManager.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; - +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services { internal interface ICoreRefreshTokenManager diff --git a/JwtAuthentication.Core/Services/IRefreshTokenManager.cs b/JwtAuthentication.Core/Services/IRefreshTokenManager.cs index aa3fb78..c501a6a 100644 --- a/JwtAuthentication.Core/Services/IRefreshTokenManager.cs +++ b/JwtAuthentication.Core/Services/IRefreshTokenManager.cs @@ -1,6 +1,6 @@ using System; using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services { diff --git a/JwtAuthentication.Core/Services/ITokenManager.cs b/JwtAuthentication.Core/Services/ITokenManager.cs index 4fc6af8..1010e8d 100644 --- a/JwtAuthentication.Core/Services/ITokenManager.cs +++ b/JwtAuthentication.Core/Services/ITokenManager.cs @@ -1,5 +1,5 @@ using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services { diff --git a/JwtAuthentication.Core/Services/Implementation/CoreRefreshTokenManager.cs b/JwtAuthentication.Core/Services/Implementation/CoreRefreshTokenManager.cs index 3f0b4ac..3544d95 100644 --- a/JwtAuthentication.Core/Services/Implementation/CoreRefreshTokenManager.cs +++ b/JwtAuthentication.Core/Services/Implementation/CoreRefreshTokenManager.cs @@ -1,8 +1,8 @@ using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; - +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation { internal class CoreRefreshTokenManager : ICoreRefreshTokenManager diff --git a/JwtAuthentication.Core/Services/Implementation/RefreshService.cs b/JwtAuthentication.Core/Services/Implementation/RefreshService.cs index f6a3625..8d61f5c 100644 --- a/JwtAuthentication.Core/Services/Implementation/RefreshService.cs +++ b/JwtAuthentication.Core/Services/Implementation/RefreshService.cs @@ -1,10 +1,10 @@ using System; using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; - +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation { internal class RefreshService : ICoreRefreshService diff --git a/JwtAuthentication.Core/Services/Implementation/TokenManager.cs b/JwtAuthentication.Core/Services/Implementation/TokenManager.cs index 6149d09..77d9b3b 100644 --- a/JwtAuthentication.Core/Services/Implementation/TokenManager.cs +++ b/JwtAuthentication.Core/Services/Implementation/TokenManager.cs @@ -1,11 +1,11 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Runtime.CompilerServices; -using System.Security.Claims; +using System.Security.Claims; using System.Threading.Tasks; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; [assembly: InternalsVisibleTo("TourmalineCore.AspNetCore.JwtAuthentication.Identity")] @@ -14,25 +14,25 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementati internal class TokenManager : ITokenManager { private readonly AuthenticationOptions _options; - private readonly IUserClaimsProvider _userClaimsProvider; + private readonly IUserClaimsProvider _userClaimsProvider; private readonly IJwtTokenCreator _jwtTokenCreator; public TokenManager( AuthenticationOptions options, - IUserClaimsProvider userClaimsProvider, + IUserClaimsProvider userClaimsProvider, IJwtTokenCreator jwtTokenCreator) { _options = options; - _userClaimsProvider = userClaimsProvider; + _userClaimsProvider = userClaimsProvider; _jwtTokenCreator = jwtTokenCreator; } public async Task GenerateAccessTokenAsync(string login = null) - { - var claims = login == null - ? new List() - : await _userClaimsProvider.GetUserClaimsAsync(login); - + { + var claims = login == null + ? new List() + : await _userClaimsProvider.GetUserClaimsAsync(login); + return await _jwtTokenCreator.CreateAsync(TokenType.Access, _options.AccessTokenExpireInMinutes, claims); } } diff --git a/JwtAuthentication.Core/Signing/SigningHelper.cs b/JwtAuthentication.Core/Signing/SigningHelper.cs deleted file mode 100644 index 0843440..0000000 --- a/JwtAuthentication.Core/Signing/SigningHelper.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.Security.Cryptography; -using Microsoft.IdentityModel.Tokens; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Signing -{ - public static class SigningHelper - { - public static RsaSecurityKey GetPublicKey(string key) - { - var publicKey = Convert.FromBase64String(key); - - var rsa = RSA.Create(); - rsa.ImportSubjectPublicKeyInfo(publicKey, out _); - - return new RsaSecurityKey(rsa); - } - - public static RsaSecurityKey GetPrivateKey(string key) - { - var privateKey = Convert.FromBase64String(key); - - var rsa = RSA.Create(); - rsa.ImportRSAPrivateKey(privateKey, out _); - - return new RsaSecurityKey(rsa); - } - } -} \ No newline at end of file diff --git a/JwtAuthentication.Identity/Services/IdentityLoginService.cs b/JwtAuthentication.Identity/Services/IdentityLoginService.cs index 4f196d6..8181ab2 100644 --- a/JwtAuthentication.Identity/Services/IdentityLoginService.cs +++ b/JwtAuthentication.Identity/Services/IdentityLoginService.cs @@ -6,6 +6,7 @@ using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Services { diff --git a/JwtAuthentication.Identity/Services/RefreshTokenManager.cs b/JwtAuthentication.Identity/Services/RefreshTokenManager.cs index 10d4328..58a2ff1 100644 --- a/JwtAuthentication.Identity/Services/RefreshTokenManager.cs +++ b/JwtAuthentication.Identity/Services/RefreshTokenManager.cs @@ -5,11 +5,11 @@ using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options; - +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; + [assembly: InternalsVisibleTo("Tests")] namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Services diff --git a/JwtAuthentication.Shared/Options/AuthenticationOptions.cs b/JwtAuthentication.Shared/Options/SharedAuthenticationOptions.cs similarity index 93% rename from JwtAuthentication.Shared/Options/AuthenticationOptions.cs rename to JwtAuthentication.Shared/Options/SharedAuthenticationOptions.cs index d12d313..577ba0c 100644 --- a/JwtAuthentication.Shared/Options/AuthenticationOptions.cs +++ b/JwtAuthentication.Shared/Options/SharedAuthenticationOptions.cs @@ -1,6 +1,6 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options { - public class AuthenticationOptions + public class SharedAuthenticationOptions { private int _accessTokenExpireInMinutes; diff --git a/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs b/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs index 7bd012a..37bfd2d 100644 --- a/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs +++ b/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs @@ -13,9 +13,9 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices { public class JwtTokenCreator : IJwtTokenCreator { - private readonly AuthenticationOptions _authenticationOptions; + private readonly SharedAuthenticationOptions _authenticationOptions; - public JwtTokenCreator(AuthenticationOptions authenticationOptions) + public JwtTokenCreator(SharedAuthenticationOptions authenticationOptions) { _authenticationOptions = authenticationOptions; } diff --git a/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs b/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs index 5ac21ea..10505f4 100644 --- a/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs +++ b/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs @@ -12,9 +12,9 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices { public class JwtTokenValidator : IJwtTokenValidator { - private readonly AuthenticationOptions _authenticationOptions; + private readonly SharedAuthenticationOptions _authenticationOptions; - public JwtTokenValidator(AuthenticationOptions options) + public JwtTokenValidator(SharedAuthenticationOptions options) { _authenticationOptions = options; } From 1033b629d0769113e22b99af16fc3ebc710b5467 Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Tue, 23 Aug 2022 11:34:15 +0500 Subject: [PATCH 22/34] chore: #60: continues to split core and shared projects --- .../Tests/NetCore5.0/LoginCallbackTests.cs | 2 +- .../Tests/NetCore6.0/LoginCallbackTests.cs | 20 ++--- Examples/Tests/Units/JwtTokenCreatorTests.cs | 4 +- .../Tests/Units/JwtTokenValidatorTests.cs | 2 +- .../AuthenticationExtensions.cs | 10 ++- .../IncorrectLoginOrPasswordException.cs | 9 --- .../ErrorHandling/InvalidJwtTokenException.cs | 9 --- ...TokenIsNotInConfidenceIntervalException.cs | 9 --- .../RefreshTokenNotFoundException.cs | 9 --- ...reshTokenOrFingerprintNotFoundException.cs | 9 --- .../ErrorHandling/RegistrationException.cs | 9 --- .../Filters/RequiresPermission.cs | 31 +------- .../Middlewares/Login/LoginMiddleware.cs | 8 +- .../Middlewares/LoginWithCookieMiddleware.cs | 11 ++- .../Middlewares/Refresh/RefreshMiddleware.cs | 10 +-- .../Refresh/RefreshMiddlewareBuilder.cs | 4 +- .../CoreRefreshTokenRequestModel.cs | 4 +- .../Models/Response/AuthResponseModel.cs | 15 ---- JwtAuthentication.Core/Models/TokenModel.cs | 8 ++ .../Options/AuthenticationOptions.cs | 23 +----- .../Options/CookieAuthOptions.cs | 7 +- .../Options/LoginEndpointOptions.cs | 13 +--- .../Options/RefreshEndpointOptions.cs | 13 +--- .../Options/RefreshTokenOptions.cs | 13 +--- .../{ => Contracts}/ICoreRefreshService.cs | 14 ++-- .../ICoreRefreshTokenManager.cs | 16 ++-- .../Services/CoreRefreshService.cs | 8 +- .../CoreRefreshTokenManager.cs | 43 +++++------ .../Services/ILoginService.cs | 14 ---- .../Services/IRegistrationService.cs | 14 ---- .../Services/ITokenManager.cs | 10 --- .../Services/Implementation/RefreshService.cs | 41 ----------- .../LoginWithRefreshService.cs | 71 +++++++++--------- .../Services/RefreshTokenManager.cs | 6 +- .../TourmalineAuthenticationBuilder.cs | 2 +- .../ApplicationBuilderExtension.cs | 54 -------------- .../Extensions}/ClaimsPrincipalExtensions.cs | 2 +- .../Filters/BaseRequiresPermission.cs | 33 +++++++++ .../JwtAuthentication.Shared.csproj | 2 +- .../Refresh/IRefreshMiddlewareBuilder.cs | 17 ----- .../Refresh/Models/RefreshModel.cs | 7 -- .../Middlewares/Refresh/RefreshMiddleware.cs | 68 ----------------- .../Refresh/RefreshMiddlewareBuilder.cs | 73 ------------------- .../{TokenModel.cs => BaseTokenModel.cs} | 2 +- .../Models/Requests}/LoginRequestModel.cs | 4 +- .../Models/Requests}/LogoutRequestModel.cs | 4 +- .../Requests}/RefreshTokenRequestModel.cs | 2 +- .../Requests}/RegistrationRequestModel.cs | 2 +- .../Models/Responses/AuthResponseModel.cs | 14 ++++ ...ptions.cs => BaseAuthenticationOptions.cs} | 2 +- .../Options/BaseCookieAuthOptions.cs | 7 ++ .../Options/BaseLoginEndpointOptions.cs | 13 ++++ ...tions.cs => BaseRefreshEndpointOptions.cs} | 2 +- ...nOptions.cs => BaseRefreshTokenOptions.cs} | 2 +- .../Services/Contracts/ILoginService.cs | 14 ++++ .../Services/Contracts}/ILogoutService.cs | 6 +- .../Services/Contracts}/IRefreshService.cs | 6 +- .../Contracts}/IRefreshTokenManager.cs | 6 +- .../Contracts/IRegistrationService.cs | 14 ++++ ...CoreRefreshService.cs => ITokenManager.cs} | 6 +- .../Services}/LoginService.cs | 25 ++++--- .../Services}/TokenManager.cs | 15 ++-- .../Contracts/IJwtTokenCreator.cs | 2 +- .../TokenServices/JwtTokenCreator.cs | 8 +- .../TokenServices/JwtTokenValidator.cs | 4 +- .../Contracts}/IUserClaimsProvider.cs | 2 +- .../Contracts}/IUserCredentialsValidator.cs | 2 +- .../DefaultUserClaimsProvider.cs | 5 +- .../FakeUserCredentialValidator.cs | 5 +- 69 files changed, 299 insertions(+), 622 deletions(-) delete mode 100644 JwtAuthentication.Core/ErrorHandling/IncorrectLoginOrPasswordException.cs delete mode 100644 JwtAuthentication.Core/ErrorHandling/InvalidJwtTokenException.cs delete mode 100644 JwtAuthentication.Core/ErrorHandling/RefreshTokenIsNotInConfidenceIntervalException.cs delete mode 100644 JwtAuthentication.Core/ErrorHandling/RefreshTokenNotFoundException.cs delete mode 100644 JwtAuthentication.Core/ErrorHandling/RefreshTokenOrFingerprintNotFoundException.cs delete mode 100644 JwtAuthentication.Core/ErrorHandling/RegistrationException.cs rename JwtAuthentication.Core/Models/{Request => Requests}/CoreRefreshTokenRequestModel.cs (87%) delete mode 100644 JwtAuthentication.Core/Models/Response/AuthResponseModel.cs create mode 100644 JwtAuthentication.Core/Models/TokenModel.cs rename JwtAuthentication.Core/Services/{ => Contracts}/ICoreRefreshService.cs (71%) rename JwtAuthentication.Core/Services/{ => Contracts}/ICoreRefreshTokenManager.cs (75%) rename {JwtAuthentication.Shared => JwtAuthentication.Core}/Services/CoreRefreshService.cs (83%) rename JwtAuthentication.Core/Services/{Implementation => }/CoreRefreshTokenManager.cs (80%) delete mode 100644 JwtAuthentication.Core/Services/ILoginService.cs delete mode 100644 JwtAuthentication.Core/Services/IRegistrationService.cs delete mode 100644 JwtAuthentication.Core/Services/ITokenManager.cs delete mode 100644 JwtAuthentication.Core/Services/Implementation/RefreshService.cs rename JwtAuthentication.Core/Services/{Implementation => }/LoginWithRefreshService.cs (70%) delete mode 100644 JwtAuthentication.Shared/ApplicationBuilderExtension.cs rename {JwtAuthentication.Core/Utils => JwtAuthentication.Shared/Extensions}/ClaimsPrincipalExtensions.cs (87%) create mode 100644 JwtAuthentication.Shared/Filters/BaseRequiresPermission.cs delete mode 100644 JwtAuthentication.Shared/Middlewares/Refresh/IRefreshMiddlewareBuilder.cs delete mode 100644 JwtAuthentication.Shared/Middlewares/Refresh/Models/RefreshModel.cs delete mode 100644 JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddleware.cs delete mode 100644 JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddlewareBuilder.cs rename JwtAuthentication.Shared/Models/{TokenModel.cs => BaseTokenModel.cs} (85%) rename {JwtAuthentication.Core/Models/Request => JwtAuthentication.Shared/Models/Requests}/LoginRequestModel.cs (71%) rename {JwtAuthentication.Core/Models/Request => JwtAuthentication.Shared/Models/Requests}/LogoutRequestModel.cs (70%) rename {JwtAuthentication.Core/Models/Request => JwtAuthentication.Shared/Models/Requests}/RefreshTokenRequestModel.cs (69%) rename {JwtAuthentication.Core/Models/Request => JwtAuthentication.Shared/Models/Requests}/RegistrationRequestModel.cs (65%) create mode 100644 JwtAuthentication.Shared/Models/Responses/AuthResponseModel.cs rename JwtAuthentication.Shared/Options/{SharedAuthenticationOptions.cs => BaseAuthenticationOptions.cs} (93%) create mode 100644 JwtAuthentication.Shared/Options/BaseCookieAuthOptions.cs create mode 100644 JwtAuthentication.Shared/Options/BaseLoginEndpointOptions.cs rename JwtAuthentication.Shared/Options/{RefreshEndpointOptions.cs => BaseRefreshEndpointOptions.cs} (87%) rename JwtAuthentication.Shared/Options/{RefreshTokenOptions.cs => BaseRefreshTokenOptions.cs} (89%) create mode 100644 JwtAuthentication.Shared/Services/Contracts/ILoginService.cs rename {JwtAuthentication.Core/Services => JwtAuthentication.Shared/Services/Contracts}/ILogoutService.cs (54%) rename {JwtAuthentication.Core/Services => JwtAuthentication.Shared/Services/Contracts}/IRefreshService.cs (60%) rename {JwtAuthentication.Core/Services => JwtAuthentication.Shared/Services/Contracts}/IRefreshTokenManager.cs (71%) create mode 100644 JwtAuthentication.Shared/Services/Contracts/IRegistrationService.cs rename JwtAuthentication.Shared/Services/Contracts/{ICoreRefreshService.cs => ITokenManager.cs} (62%) rename {JwtAuthentication.Core/Services/Implementation => JwtAuthentication.Shared/Services}/LoginService.cs (69%) rename {JwtAuthentication.Core/Services/Implementation => JwtAuthentication.Shared/Services}/TokenManager.cs (66%) rename {JwtAuthentication.Core/Contract => JwtAuthentication.Shared/UserServices/Contracts}/IUserClaimsProvider.cs (71%) rename {JwtAuthentication.Core/Contract => JwtAuthentication.Shared/UserServices/Contracts}/IUserCredentialsValidator.cs (66%) rename {JwtAuthentication.Core/Contract/Implementation => JwtAuthentication.Shared/UserServices}/DefaultUserClaimsProvider.cs (63%) rename {JwtAuthentication.Core/Contract/Implementation => JwtAuthentication.Shared/UserServices}/FakeUserCredentialValidator.cs (58%) diff --git a/Examples/Tests/NetCore5.0/LoginCallbackTests.cs b/Examples/Tests/NetCore5.0/LoginCallbackTests.cs index d0b22e8..19805ed 100644 --- a/Examples/Tests/NetCore5.0/LoginCallbackTests.cs +++ b/Examples/Tests/NetCore5.0/LoginCallbackTests.cs @@ -8,7 +8,7 @@ using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services; using Xunit; namespace Tests.NetCore5._0 diff --git a/Examples/Tests/NetCore6.0/LoginCallbackTests.cs b/Examples/Tests/NetCore6.0/LoginCallbackTests.cs index f60752d..dff0ea6 100644 --- a/Examples/Tests/NetCore6.0/LoginCallbackTests.cs +++ b/Examples/Tests/NetCore6.0/LoginCallbackTests.cs @@ -2,13 +2,13 @@ using Microsoft.AspNetCore.Http; using Moq; using Newtonsoft.Json; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract.Implementation; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices; using Xunit; namespace Tests.NetCore6._0 @@ -45,14 +45,14 @@ public LoginCallbackTests() _onLoginExecutedMock.Setup(p => p(It.IsAny())) .Returns(Task.CompletedTask); - - var authenticationOptions = new AuthenticationOptions() - { - PrivateSigningKey = "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU", - }; - - _loginService = new LoginService( - new TokenManager(authenticationOptions, new DefaultUserClaimsProvider(), new JwtTokenCreator(authenticationOptions)), + + var authenticationOptions = new AuthenticationOptions() + { + PrivateSigningKey = "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU", + }; + + _loginService = new LoginService( + new TokenManager(authenticationOptions, new DefaultUserClaimsProvider(), new JwtTokenCreator(authenticationOptions)), new FakeUserCredentialValidator()); } diff --git a/Examples/Tests/Units/JwtTokenCreatorTests.cs b/Examples/Tests/Units/JwtTokenCreatorTests.cs index 45c1f30..48ae0e4 100644 --- a/Examples/Tests/Units/JwtTokenCreatorTests.cs +++ b/Examples/Tests/Units/JwtTokenCreatorTests.cs @@ -16,7 +16,7 @@ public class JwtTokenCreatorTests public JwtTokenCreatorTests() { - var authenticationOptions = new SharedAuthenticationOptions() + var authenticationOptions = new BaseAuthenticationOptions() { PrivateSigningKey = "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU", }; @@ -95,7 +95,7 @@ private Claim GetClaim(string tokenValue, string claimType) return token.Claims.SingleOrDefault(claim => claim.Type == claimType); } - private Claim GetTokenTypeClaim(TokenModel tokenModel) + private Claim GetTokenTypeClaim(BaseTokenModel tokenModel) { return GetClaim(tokenModel.Value, Consts.TokenTypeClaimName); } diff --git a/Examples/Tests/Units/JwtTokenValidatorTests.cs b/Examples/Tests/Units/JwtTokenValidatorTests.cs index 84bc9b6..a64a78c 100644 --- a/Examples/Tests/Units/JwtTokenValidatorTests.cs +++ b/Examples/Tests/Units/JwtTokenValidatorTests.cs @@ -16,7 +16,7 @@ public class JwtTokenValidatorTests public JwtTokenValidatorTests() { - var authenticationOptions = new SharedAuthenticationOptions() + var authenticationOptions = new BaseAuthenticationOptions() { PublicSigningKey = PublicSigningKey }; diff --git a/JwtAuthentication.Core/AuthenticationExtensions.cs b/JwtAuthentication.Core/AuthenticationExtensions.cs index 4360356..4243830 100644 --- a/JwtAuthentication.Core/AuthenticationExtensions.cs +++ b/JwtAuthentication.Core/AuthenticationExtensions.cs @@ -5,17 +5,19 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract.Implementation; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Filters; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Core.TokenHandlers; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Signing; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; using AuthenticationOptions = TourmalineCore.AspNetCore.JwtAuthentication.Core.Options.AuthenticationOptions; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core { @@ -95,7 +97,7 @@ public static IServiceCollection AddLoginWithRefresh( services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddTransient(); + services.AddTransient(); return services; } diff --git a/JwtAuthentication.Core/ErrorHandling/IncorrectLoginOrPasswordException.cs b/JwtAuthentication.Core/ErrorHandling/IncorrectLoginOrPasswordException.cs deleted file mode 100644 index f5f7f3c..0000000 --- a/JwtAuthentication.Core/ErrorHandling/IncorrectLoginOrPasswordException.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling -{ - public class IncorrectLoginOrPasswordException : Exception - { - public IncorrectLoginOrPasswordException() : base("Incorrect login or password") { } - } -} diff --git a/JwtAuthentication.Core/ErrorHandling/InvalidJwtTokenException.cs b/JwtAuthentication.Core/ErrorHandling/InvalidJwtTokenException.cs deleted file mode 100644 index 1d8d2fc..0000000 --- a/JwtAuthentication.Core/ErrorHandling/InvalidJwtTokenException.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling -{ - public class InvalidJwtTokenException : Exception - { - public InvalidJwtTokenException() : base("Invalid jwt token") { } - } -} diff --git a/JwtAuthentication.Core/ErrorHandling/RefreshTokenIsNotInConfidenceIntervalException.cs b/JwtAuthentication.Core/ErrorHandling/RefreshTokenIsNotInConfidenceIntervalException.cs deleted file mode 100644 index f683dec..0000000 --- a/JwtAuthentication.Core/ErrorHandling/RefreshTokenIsNotInConfidenceIntervalException.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling -{ - public class RefreshTokenIsNotInConfidenceIntervalException : Exception - { - public RefreshTokenIsNotInConfidenceIntervalException() : base("Refresh token is not in confidence interval") { } - } -} diff --git a/JwtAuthentication.Core/ErrorHandling/RefreshTokenNotFoundException.cs b/JwtAuthentication.Core/ErrorHandling/RefreshTokenNotFoundException.cs deleted file mode 100644 index c17a1d6..0000000 --- a/JwtAuthentication.Core/ErrorHandling/RefreshTokenNotFoundException.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling -{ - internal class RefreshTokenNotFoundException : Exception - { - public RefreshTokenNotFoundException() : base("Refresh token not found") { } - } -} diff --git a/JwtAuthentication.Core/ErrorHandling/RefreshTokenOrFingerprintNotFoundException.cs b/JwtAuthentication.Core/ErrorHandling/RefreshTokenOrFingerprintNotFoundException.cs deleted file mode 100644 index 06aa60a..0000000 --- a/JwtAuthentication.Core/ErrorHandling/RefreshTokenOrFingerprintNotFoundException.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling -{ - public class RefreshTokenOrFingerprintNotFoundException : Exception - { - public RefreshTokenOrFingerprintNotFoundException() : base("Refresh token or fingerprint not found") { } - } -} diff --git a/JwtAuthentication.Core/ErrorHandling/RegistrationException.cs b/JwtAuthentication.Core/ErrorHandling/RegistrationException.cs deleted file mode 100644 index 85c6f29..0000000 --- a/JwtAuthentication.Core/ErrorHandling/RegistrationException.cs +++ /dev/null @@ -1,9 +0,0 @@ -using System; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling -{ - public class RegistrationException : Exception - { - public RegistrationException() : base("An registration exception occured") { } - } -} \ No newline at end of file diff --git a/JwtAuthentication.Core/Filters/RequiresPermission.cs b/JwtAuthentication.Core/Filters/RequiresPermission.cs index 3bb5d53..808cc7a 100644 --- a/JwtAuthentication.Core/Filters/RequiresPermission.cs +++ b/JwtAuthentication.Core/Filters/RequiresPermission.cs @@ -1,33 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Utils; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Filters; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Filters { - public class RequiresPermission : Attribute, IAuthorizationFilter - { - internal static string ClaimType; - - private readonly List _permissions; - - public RequiresPermission(params string[] permissions) - { - _permissions = permissions.ToList(); - } - - public void OnAuthorization(AuthorizationFilterContext context) - { - var user = context.HttpContext.User; - - if (_permissions.Any(x => user.HasPermission(ClaimType, x))) - { - return; - } - - context.Result = new ForbidResult(); - } - } + public class RequiresPermission : BaseRequiresPermission { } } \ No newline at end of file diff --git a/JwtAuthentication.Core/Middlewares/Login/LoginMiddleware.cs b/JwtAuthentication.Core/Middlewares/Login/LoginMiddleware.cs index 0f007f3..9894f47 100644 --- a/JwtAuthentication.Core/Middlewares/Login/LoginMiddleware.cs +++ b/JwtAuthentication.Core/Middlewares/Login/LoginMiddleware.cs @@ -2,10 +2,10 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login { @@ -51,7 +51,7 @@ protected override async Task ExecuteServiceMethod( } catch (Exception ex) { - context.Response.StatusCode = StatusCodes.Status401Unauthorized; + context.Response.StatusCode = StatusCodes.Status401Unauthorized; throw new Exception(ex.Message); } diff --git a/JwtAuthentication.Core/Middlewares/LoginWithCookieMiddleware.cs b/JwtAuthentication.Core/Middlewares/LoginWithCookieMiddleware.cs index 8ed00a4..ee26fef 100644 --- a/JwtAuthentication.Core/Middlewares/LoginWithCookieMiddleware.cs +++ b/JwtAuthentication.Core/Middlewares/LoginWithCookieMiddleware.cs @@ -1,11 +1,10 @@ -using System; +using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares { @@ -54,7 +53,7 @@ protected override async Task ExecuteServiceMethod( } catch (Exception ex) { - context.Response.StatusCode = StatusCodes.Status401Unauthorized; + context.Response.StatusCode = StatusCodes.Status401Unauthorized; throw new Exception(ex.Message); } diff --git a/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs b/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs index 41aeb6d..86e21ff 100644 --- a/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs +++ b/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs @@ -3,14 +3,14 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Requests; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh { - internal class RefreshMiddleware : RequestMiddlewareBase + internal class RefreshMiddleware : RequestMiddlewareBase { private readonly RefreshEndpointOptions _endpointOptions; private readonly ILogger _logger; @@ -37,12 +37,12 @@ public async Task InvokeAsync(HttpContext context, ICoreRefreshService refreshSe await InvokeAsyncBase(context, refreshService, _endpointOptions.RefreshEndpointRoute); } - protected override async Task ExecuteServiceMethod( + protected override async Task ExecuteServiceMethod( CoreRefreshTokenRequestModel requestModel, ICoreRefreshService service, HttpContext context) { - var result = new TokenModel(); + var result = new BaseTokenModel(); try { diff --git a/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddlewareBuilder.cs b/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddlewareBuilder.cs index 3826b79..e63fefc 100644 --- a/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddlewareBuilder.cs +++ b/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddlewareBuilder.cs @@ -1,8 +1,8 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh { diff --git a/JwtAuthentication.Core/Models/Request/CoreRefreshTokenRequestModel.cs b/JwtAuthentication.Core/Models/Requests/CoreRefreshTokenRequestModel.cs similarity index 87% rename from JwtAuthentication.Core/Models/Request/CoreRefreshTokenRequestModel.cs rename to JwtAuthentication.Core/Models/Requests/CoreRefreshTokenRequestModel.cs index 642c725..3b3688f 100644 --- a/JwtAuthentication.Core/Models/Request/CoreRefreshTokenRequestModel.cs +++ b/JwtAuthentication.Core/Models/Requests/CoreRefreshTokenRequestModel.cs @@ -1,6 +1,4 @@ -using System; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Requests { public class CoreRefreshTokenRequestModel { diff --git a/JwtAuthentication.Core/Models/Response/AuthResponseModel.cs b/JwtAuthentication.Core/Models/Response/AuthResponseModel.cs deleted file mode 100644 index 9072485..0000000 --- a/JwtAuthentication.Core/Models/Response/AuthResponseModel.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Runtime.CompilerServices; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; - -[assembly: InternalsVisibleTo("TourmalineCore.AspNetCore.JwtAuthentication.Identity")] -[assembly: InternalsVisibleTo("Tests")] - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response -{ - internal class AuthResponseModel - { - public TokenModel AccessToken { get; set; } - - public TokenModel RefreshToken { get; set; } - } -} \ No newline at end of file diff --git a/JwtAuthentication.Core/Models/TokenModel.cs b/JwtAuthentication.Core/Models/TokenModel.cs new file mode 100644 index 0000000..ae33eca --- /dev/null +++ b/JwtAuthentication.Core/Models/TokenModel.cs @@ -0,0 +1,8 @@ +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Models +{ + public class TokenModel : BaseTokenModel + { + } +} diff --git a/JwtAuthentication.Core/Options/AuthenticationOptions.cs b/JwtAuthentication.Core/Options/AuthenticationOptions.cs index 176ca3f..a175469 100644 --- a/JwtAuthentication.Core/Options/AuthenticationOptions.cs +++ b/JwtAuthentication.Core/Options/AuthenticationOptions.cs @@ -1,23 +1,6 @@ +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Options { - public class AuthenticationOptions - { - private int _accessTokenExpireInMinutes; - - public string PublicSigningKey { get; set; } - - public string PrivateSigningKey { get; set; } - - public string Issuer { get; set; } - - public string Audience { get; set; } - - public virtual int AccessTokenExpireInMinutes - { - get => _accessTokenExpireInMinutes == default ? 10080 : _accessTokenExpireInMinutes; - set => _accessTokenExpireInMinutes = value; - } - - public bool IsDebugTokenEnabled { get; set; } - } + public class AuthenticationOptions : BaseAuthenticationOptions { } } \ No newline at end of file diff --git a/JwtAuthentication.Core/Options/CookieAuthOptions.cs b/JwtAuthentication.Core/Options/CookieAuthOptions.cs index 5199f37..cda049c 100644 --- a/JwtAuthentication.Core/Options/CookieAuthOptions.cs +++ b/JwtAuthentication.Core/Options/CookieAuthOptions.cs @@ -1,7 +1,6 @@ +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Options { - public class CookieAuthOptions - { - public string Key { get; set; } - } + public class CookieAuthOptions : BaseCookieAuthOptions { } } \ No newline at end of file diff --git a/JwtAuthentication.Core/Options/LoginEndpointOptions.cs b/JwtAuthentication.Core/Options/LoginEndpointOptions.cs index 48896c6..7462054 100644 --- a/JwtAuthentication.Core/Options/LoginEndpointOptions.cs +++ b/JwtAuthentication.Core/Options/LoginEndpointOptions.cs @@ -1,13 +1,6 @@ +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Options { - public class LoginEndpointOptions - { - private string _loginEndpointRoute; - - public string LoginEndpointRoute - { - get => _loginEndpointRoute ?? "/auth/login"; - set => _loginEndpointRoute = value; - } - } + public class LoginEndpointOptions : BaseLoginEndpointOptions { } } \ No newline at end of file diff --git a/JwtAuthentication.Core/Options/RefreshEndpointOptions.cs b/JwtAuthentication.Core/Options/RefreshEndpointOptions.cs index d5aa1c3..a30f402 100644 --- a/JwtAuthentication.Core/Options/RefreshEndpointOptions.cs +++ b/JwtAuthentication.Core/Options/RefreshEndpointOptions.cs @@ -1,13 +1,6 @@ +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Options { - public class RefreshEndpointOptions - { - private string _refreshEndpointRoute; - - public string RefreshEndpointRoute - { - get => _refreshEndpointRoute ?? "/auth/refresh"; - set => _refreshEndpointRoute = value; - } - } + public class RefreshEndpointOptions : BaseRefreshEndpointOptions { } } \ No newline at end of file diff --git a/JwtAuthentication.Core/Options/RefreshTokenOptions.cs b/JwtAuthentication.Core/Options/RefreshTokenOptions.cs index 609bd97..af00f8c 100644 --- a/JwtAuthentication.Core/Options/RefreshTokenOptions.cs +++ b/JwtAuthentication.Core/Options/RefreshTokenOptions.cs @@ -1,13 +1,6 @@ +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Options { - public class RefreshTokenOptions - { - private int _refreshTokenExpireInMinutes; - - public int RefreshTokenExpireInMinutes - { - get => _refreshTokenExpireInMinutes == default ? 10080 : _refreshTokenExpireInMinutes; - set => _refreshTokenExpireInMinutes = value; - } - } + public class RefreshTokenOptions : BaseRefreshTokenOptions { } } diff --git a/JwtAuthentication.Core/Services/ICoreRefreshService.cs b/JwtAuthentication.Core/Services/Contracts/ICoreRefreshService.cs similarity index 71% rename from JwtAuthentication.Core/Services/ICoreRefreshService.cs rename to JwtAuthentication.Core/Services/Contracts/ICoreRefreshService.cs index 75d60d2..db6674a 100644 --- a/JwtAuthentication.Core/Services/ICoreRefreshService.cs +++ b/JwtAuthentication.Core/Services/Contracts/ICoreRefreshService.cs @@ -1,10 +1,10 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services -{ - internal interface ICoreRefreshService - { - public Task RefreshAsync(string jwtRefreshToken); - } +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts +{ + internal interface ICoreRefreshService + { + public Task RefreshAsync(string jwtRefreshToken); + } } \ No newline at end of file diff --git a/JwtAuthentication.Core/Services/ICoreRefreshTokenManager.cs b/JwtAuthentication.Core/Services/Contracts/ICoreRefreshTokenManager.cs similarity index 75% rename from JwtAuthentication.Core/Services/ICoreRefreshTokenManager.cs rename to JwtAuthentication.Core/Services/Contracts/ICoreRefreshTokenManager.cs index 57168d7..dcc86dd 100644 --- a/JwtAuthentication.Core/Services/ICoreRefreshTokenManager.cs +++ b/JwtAuthentication.Core/Services/Contracts/ICoreRefreshTokenManager.cs @@ -1,10 +1,10 @@ -using System.Threading.Tasks; +using System.Threading.Tasks; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services -{ - internal interface ICoreRefreshTokenManager - { - Task GenerateRefreshTokenAsync(); - } -} +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts +{ + internal interface ICoreRefreshTokenManager + { + Task GenerateRefreshTokenAsync(); + } +} diff --git a/JwtAuthentication.Shared/Services/CoreRefreshService.cs b/JwtAuthentication.Core/Services/CoreRefreshService.cs similarity index 83% rename from JwtAuthentication.Shared/Services/CoreRefreshService.cs rename to JwtAuthentication.Core/Services/CoreRefreshService.cs index e1da234..8c5da08 100644 --- a/JwtAuthentication.Shared/Services/CoreRefreshService.cs +++ b/JwtAuthentication.Core/Services/CoreRefreshService.cs @@ -1,14 +1,14 @@ using System; using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Errors; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services { - public class CoreRefreshService : ICoreRefreshService + internal class CoreRefreshService : ICoreRefreshService { private readonly IJwtTokenValidator _jwtTokenValidator; private readonly IJwtTokenCreator _jwtTokenCreator; @@ -24,7 +24,7 @@ public CoreRefreshService( _refreshTokenOptions = refreshTokenOptions; } - public async Task RefreshAsync(string tokenValue) + public async Task RefreshAsync(string tokenValue) { try { diff --git a/JwtAuthentication.Core/Services/Implementation/CoreRefreshTokenManager.cs b/JwtAuthentication.Core/Services/CoreRefreshTokenManager.cs similarity index 80% rename from JwtAuthentication.Core/Services/Implementation/CoreRefreshTokenManager.cs rename to JwtAuthentication.Core/Services/CoreRefreshTokenManager.cs index 3544d95..526b38a 100644 --- a/JwtAuthentication.Core/Services/Implementation/CoreRefreshTokenManager.cs +++ b/JwtAuthentication.Core/Services/CoreRefreshTokenManager.cs @@ -1,24 +1,25 @@ -using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation -{ - internal class CoreRefreshTokenManager : ICoreRefreshTokenManager - { - private readonly IJwtTokenCreator _jwtTokenCreator; - private readonly RefreshTokenOptions _refreshTokenOptions; - - public CoreRefreshTokenManager(IJwtTokenCreator jwtTokenCreator, RefreshTokenOptions refreshTokenOptions) - { - _jwtTokenCreator = jwtTokenCreator; - _refreshTokenOptions = refreshTokenOptions; - } - - public Task GenerateRefreshTokenAsync() - { - return _jwtTokenCreator.CreateAsync(TokenType.Refresh, _refreshTokenOptions.RefreshTokenExpireInMinutes); - } - } -} +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services +{ + internal class CoreRefreshTokenManager : ICoreRefreshTokenManager + { + private readonly IJwtTokenCreator _jwtTokenCreator; + private readonly RefreshTokenOptions _refreshTokenOptions; + + public CoreRefreshTokenManager(IJwtTokenCreator jwtTokenCreator, RefreshTokenOptions refreshTokenOptions) + { + _jwtTokenCreator = jwtTokenCreator; + _refreshTokenOptions = refreshTokenOptions; + } + + public Task GenerateRefreshTokenAsync() + { + return _jwtTokenCreator.CreateAsync(TokenType.Refresh, _refreshTokenOptions.RefreshTokenExpireInMinutes); + } + } +} diff --git a/JwtAuthentication.Core/Services/ILoginService.cs b/JwtAuthentication.Core/Services/ILoginService.cs deleted file mode 100644 index 9a2493d..0000000 --- a/JwtAuthentication.Core/Services/ILoginService.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; - -[assembly: InternalsVisibleTo("TourmalineCore.AspNetCore.JwtAuthentication.Identity")] - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services -{ - internal interface ILoginService - { - public Task LoginAsync(LoginRequestModel model); - } -} \ No newline at end of file diff --git a/JwtAuthentication.Core/Services/IRegistrationService.cs b/JwtAuthentication.Core/Services/IRegistrationService.cs deleted file mode 100644 index 379595d..0000000 --- a/JwtAuthentication.Core/Services/IRegistrationService.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services -{ - internal interface IRegistrationService - where TUser : class - where TRegistrationRequestModel : RegistrationRequestModel - { - Task RegisterAsync(TRegistrationRequestModel model, Func mapping); - } -} \ No newline at end of file diff --git a/JwtAuthentication.Core/Services/ITokenManager.cs b/JwtAuthentication.Core/Services/ITokenManager.cs deleted file mode 100644 index 1010e8d..0000000 --- a/JwtAuthentication.Core/Services/ITokenManager.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services -{ - internal interface ITokenManager - { - Task GenerateAccessTokenAsync(string login = null); - } -} \ No newline at end of file diff --git a/JwtAuthentication.Core/Services/Implementation/RefreshService.cs b/JwtAuthentication.Core/Services/Implementation/RefreshService.cs deleted file mode 100644 index 8d61f5c..0000000 --- a/JwtAuthentication.Core/Services/Implementation/RefreshService.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation -{ - internal class RefreshService : ICoreRefreshService - { - private readonly IJwtTokenValidator _jwtTokenValidator; - private readonly IJwtTokenCreator _jwtTokenCreator; - private readonly RefreshTokenOptions _refreshTokenOptions; - - public RefreshService( - IJwtTokenValidator jwtTokenValidator, - IJwtTokenCreator jwtTokenCreator, - RefreshTokenOptions refreshTokenOptions) - { - _jwtTokenValidator = jwtTokenValidator; - _jwtTokenCreator = jwtTokenCreator; - _refreshTokenOptions = refreshTokenOptions; - } - - public async Task RefreshAsync(string tokenValue) - { - try - { - await _jwtTokenValidator.ValidateTokenAsync(tokenValue); - await _jwtTokenValidator.ValidateTokenTypeAsync(tokenValue, TokenType.Refresh); - - return await _jwtTokenCreator.CreateAsync(TokenType.Refresh, _refreshTokenOptions.RefreshTokenExpireInMinutes); - } - catch (Exception) - { - throw new InvalidJwtTokenException(); - } - } - } -} diff --git a/JwtAuthentication.Core/Services/Implementation/LoginWithRefreshService.cs b/JwtAuthentication.Core/Services/LoginWithRefreshService.cs similarity index 70% rename from JwtAuthentication.Core/Services/Implementation/LoginWithRefreshService.cs rename to JwtAuthentication.Core/Services/LoginWithRefreshService.cs index 9926bcf..6a1b5b9 100644 --- a/JwtAuthentication.Core/Services/Implementation/LoginWithRefreshService.cs +++ b/JwtAuthentication.Core/Services/LoginWithRefreshService.cs @@ -1,34 +1,37 @@ -using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation -{ - internal class LoginWithRefreshService : LoginService - { - private readonly ITokenManager _tokenManager; - private readonly ICoreRefreshTokenManager _refreshTokenManager; - - public LoginWithRefreshService( - ITokenManager tokenManager, - ICoreRefreshTokenManager refreshTokenManager, - IUserCredentialsValidator userCredentialsValidator = null) - : base(tokenManager, userCredentialsValidator) - { - _tokenManager = tokenManager; - _refreshTokenManager = refreshTokenManager; - } - - public override async Task LoginAsync(LoginRequestModel model) - { - await base.ValidateCredentials(model); - - return new AuthResponseModel - { - AccessToken = await _tokenManager.GenerateAccessTokenAsync(model.Login), - RefreshToken = await _refreshTokenManager.GenerateRefreshTokenAsync(), - }; - } - } -} +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services +{ + internal class LoginWithRefreshService : LoginService + { + private readonly ITokenManager _tokenManager; + private readonly ICoreRefreshTokenManager _refreshTokenManager; + + public LoginWithRefreshService( + ITokenManager tokenManager, + ICoreRefreshTokenManager refreshTokenManager, + IUserCredentialsValidator userCredentialsValidator = null) + : base(tokenManager, userCredentialsValidator) + { + _tokenManager = tokenManager; + _refreshTokenManager = refreshTokenManager; + } + + public override async Task LoginAsync(LoginRequestModel model) + { + await base.ValidateCredentials(model); + + return new AuthResponseModel + { + AccessToken = await _tokenManager.GenerateAccessTokenAsync(model.Login), + RefreshToken = await _refreshTokenManager.GenerateRefreshTokenAsync(), + }; + } + } +} diff --git a/JwtAuthentication.Identity/Services/RefreshTokenManager.cs b/JwtAuthentication.Identity/Services/RefreshTokenManager.cs index 58a2ff1..35d1927 100644 --- a/JwtAuthentication.Identity/Services/RefreshTokenManager.cs +++ b/JwtAuthentication.Identity/Services/RefreshTokenManager.cs @@ -39,7 +39,7 @@ public RefreshTokenManager( _options = options; } - public async Task GenerateRefreshTokenAsync(object user, string clientFingerPrint) + public async Task GenerateRefreshTokenAsync(object user, string clientFingerPrint) { var refreshToken = CreateRefreshToken(user, clientFingerPrint); @@ -127,9 +127,9 @@ private RefreshToken CreateRefreshToken(object user, string clientF return newToken; } - private static TokenModel BuildTokenModelByRefreshToken(RefreshToken refreshToken) + private static BaseTokenModel BuildTokenModelByRefreshToken(RefreshToken refreshToken) { - return new TokenModel + return new BaseTokenModel { Value = refreshToken.Value.ToString(), ExpiresInUtc = refreshToken.ExpiresIn.ToUniversalTime(), diff --git a/JwtAuthentication.Identity/TourmalineAuthenticationBuilder.cs b/JwtAuthentication.Identity/TourmalineAuthenticationBuilder.cs index 6397298..c336cbe 100644 --- a/JwtAuthentication.Identity/TourmalineAuthenticationBuilder.cs +++ b/JwtAuthentication.Identity/TourmalineAuthenticationBuilder.cs @@ -8,7 +8,7 @@ using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Validators; diff --git a/JwtAuthentication.Shared/ApplicationBuilderExtension.cs b/JwtAuthentication.Shared/ApplicationBuilderExtension.cs deleted file mode 100644 index 8d76098..0000000 --- a/JwtAuthentication.Shared/ApplicationBuilderExtension.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared -{ - public static class ApplicationBuilderExtension - { - /// - /// Adds middleware to handle incoming login and token refresh requests. - /// - /// - /// - /// - public static IApplicationBuilder UseRefreshTokenMiddleware(this IApplicationBuilder applicationBuilder, RefreshEndpointOptions endpointOptions = null) - { - Func defaultOnRefreshCallback = s => Task.CompletedTask; - - return applicationBuilder - .UseMiddleware(endpointOptions ?? new RefreshEndpointOptions(), defaultOnRefreshCallback, defaultOnRefreshCallback); - } - - /// - /// Registering a callback function to perform actions when when the refresh starts. - /// - /// - /// - /// - public static IRefreshMiddlewareBuilder OnRefreshExecuting(this IApplicationBuilder applicationBuilder, Func callback) - { - return RefreshMiddlewareBuilder - .GetInstance() - .SetAppBuilder(applicationBuilder) - .OnRefreshExecuting(callback); - } - - /// - /// Registering a callback function to perform actions when the refresh ends. - /// - /// - /// - /// - public static IRefreshMiddlewareBuilder OnRefreshExecuted(this IApplicationBuilder applicationBuilder, Func callback) - { - return RefreshMiddlewareBuilder - .GetInstance() - .SetAppBuilder(applicationBuilder) - .OnRefreshExecuted(callback); - } - } -} \ No newline at end of file diff --git a/JwtAuthentication.Core/Utils/ClaimsPrincipalExtensions.cs b/JwtAuthentication.Shared/Extensions/ClaimsPrincipalExtensions.cs similarity index 87% rename from JwtAuthentication.Core/Utils/ClaimsPrincipalExtensions.cs rename to JwtAuthentication.Shared/Extensions/ClaimsPrincipalExtensions.cs index cd22ff0..d2f4932 100644 --- a/JwtAuthentication.Core/Utils/ClaimsPrincipalExtensions.cs +++ b/JwtAuthentication.Shared/Extensions/ClaimsPrincipalExtensions.cs @@ -2,7 +2,7 @@ using System.Linq; using System.Security.Claims; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Utils +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Extensions { internal static class ClaimsPrincipalExtensions { diff --git a/JwtAuthentication.Shared/Filters/BaseRequiresPermission.cs b/JwtAuthentication.Shared/Filters/BaseRequiresPermission.cs new file mode 100644 index 0000000..e6871b2 --- /dev/null +++ b/JwtAuthentication.Shared/Filters/BaseRequiresPermission.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Extensions; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Filters +{ + public class BaseRequiresPermission : Attribute, IAuthorizationFilter + { + public static string ClaimType; + + private readonly List _permissions; + + public BaseRequiresPermission(params string[] permissions) + { + _permissions = permissions.ToList(); + } + + public void OnAuthorization(AuthorizationFilterContext context) + { + var user = context.HttpContext.User; + + if (_permissions.Any(x => user.HasPermission(ClaimType, x))) + { + return; + } + + context.Result = new ForbidResult(); + } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/JwtAuthentication.Shared.csproj b/JwtAuthentication.Shared/JwtAuthentication.Shared.csproj index b6d363c..d0f913b 100644 --- a/JwtAuthentication.Shared/JwtAuthentication.Shared.csproj +++ b/JwtAuthentication.Shared/JwtAuthentication.Shared.csproj @@ -1,4 +1,4 @@ - + netcoreapp3.1;net5.0;net6.0 diff --git a/JwtAuthentication.Shared/Middlewares/Refresh/IRefreshMiddlewareBuilder.cs b/JwtAuthentication.Shared/Middlewares/Refresh/IRefreshMiddlewareBuilder.cs deleted file mode 100644 index d4fff0c..0000000 --- a/JwtAuthentication.Shared/Middlewares/Refresh/IRefreshMiddlewareBuilder.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh -{ - public interface IRefreshMiddlewareBuilder - { - public IRefreshMiddlewareBuilder OnRefreshExecuting(Func callback); - - public IRefreshMiddlewareBuilder OnRefreshExecuted(Func callback); - - public IApplicationBuilder UseRefreshMiddleware(RefreshEndpointOptions refreshEndpointOptions = null); - } -} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Middlewares/Refresh/Models/RefreshModel.cs b/JwtAuthentication.Shared/Middlewares/Refresh/Models/RefreshModel.cs deleted file mode 100644 index 6bac81a..0000000 --- a/JwtAuthentication.Shared/Middlewares/Refresh/Models/RefreshModel.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh.Models -{ - public class RefreshModel - { - public string RefreshTokenValue { get; set; } - } -} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddleware.cs b/JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddleware.cs deleted file mode 100644 index 4c1567d..0000000 --- a/JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddleware.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh -{ - public class RefreshMiddleware : RequestMiddlewareBase - { - private readonly RefreshEndpointOptions _endpointOptions; - private readonly ILogger _logger; - - private readonly Func _onRefreshExecuting; - private readonly Func _onRefreshExecuted; - - public RefreshMiddleware( - RequestDelegate next, - RefreshEndpointOptions endpointOptions, - ILogger logger, - Func onRefreshExecuting, - Func onRefreshExecuted) - : base(next) - { - _endpointOptions = endpointOptions; - _logger = logger; - _onRefreshExecuting = onRefreshExecuting; - _onRefreshExecuted = onRefreshExecuted; - } - - public async Task InvokeAsync(HttpContext context, ICoreRefreshService refreshService) - { - await InvokeAsyncBase(context, refreshService, _endpointOptions.RefreshEndpointRoute); - } - - protected override async Task ExecuteServiceMethod( - CoreRefreshTokenRequest requestModel, - ICoreRefreshService service, - HttpContext context) - { - var result = new TokenModel(); - - try - { - var contractRefreshModel = new RefreshModel - { - RefreshTokenValue = requestModel.RefreshTokenValue, - }; - - await _onRefreshExecuting(contractRefreshModel); - result = await service.RefreshAsync(contractRefreshModel.RefreshTokenValue); - await _onRefreshExecuted(contractRefreshModel); - } - catch (Exception ex) - { - context.Response.StatusCode = StatusCodes.Status409Conflict; - _logger.LogError(ex.ToString()); - throw new Exception(ex.Message); - } - - return result; - } - } -} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddlewareBuilder.cs b/JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddlewareBuilder.cs deleted file mode 100644 index 372e711..0000000 --- a/JwtAuthentication.Shared/Middlewares/Refresh/RefreshMiddlewareBuilder.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Refresh -{ - public class RefreshMiddlewareBuilder : IRefreshMiddlewareBuilder - { - private static Func _onRefreshExecutingCallback = s => Task.CompletedTask; - private static Func _onRefreshExecutedCallback = s => Task.CompletedTask; - - private IApplicationBuilder _applicationBuilder; - - private static RefreshMiddlewareBuilder _instance; - - private RefreshMiddlewareBuilder() - { - } - - internal static RefreshMiddlewareBuilder GetInstance() - { - if (_instance != null) - { - return _instance; - } - - _instance = new RefreshMiddlewareBuilder(); - - return _instance; - } - - internal IRefreshMiddlewareBuilder SetAppBuilder(IApplicationBuilder applicationBuilder) - { - _applicationBuilder = applicationBuilder; - return this; - } - - /// - /// Registering a callback function to perform actions when when the refresh starts. - /// - /// - /// - public IRefreshMiddlewareBuilder OnRefreshExecuting(Func callback) - { - _onRefreshExecutingCallback = callback; - return this; - } - - /// - /// Registering a callback function to perform actions when the refresh ends. - /// - /// - /// - public IRefreshMiddlewareBuilder OnRefreshExecuted(Func callback) - { - _onRefreshExecutedCallback = callback; - return this; - } - - /// - /// Adds middleware to handle incoming logout requests. - /// - /// - /// - public IApplicationBuilder UseRefreshMiddleware(RefreshEndpointOptions refreshEndpointOptions = null) - { - return _applicationBuilder - .UseMiddleware(refreshEndpointOptions ?? new RefreshEndpointOptions(), _onRefreshExecutingCallback, _onRefreshExecutedCallback); - } - } -} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Models/TokenModel.cs b/JwtAuthentication.Shared/Models/BaseTokenModel.cs similarity index 85% rename from JwtAuthentication.Shared/Models/TokenModel.cs rename to JwtAuthentication.Shared/Models/BaseTokenModel.cs index ffb5302..aaab9a2 100644 --- a/JwtAuthentication.Shared/Models/TokenModel.cs +++ b/JwtAuthentication.Shared/Models/BaseTokenModel.cs @@ -2,7 +2,7 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models { - public class TokenModel + public class BaseTokenModel { public string Value { get; set; } diff --git a/JwtAuthentication.Core/Models/Request/LoginRequestModel.cs b/JwtAuthentication.Shared/Models/Requests/LoginRequestModel.cs similarity index 71% rename from JwtAuthentication.Core/Models/Request/LoginRequestModel.cs rename to JwtAuthentication.Shared/Models/Requests/LoginRequestModel.cs index d0acb0d..ef097fd 100644 --- a/JwtAuthentication.Core/Models/Request/LoginRequestModel.cs +++ b/JwtAuthentication.Shared/Models/Requests/LoginRequestModel.cs @@ -2,9 +2,9 @@ [assembly: InternalsVisibleTo("TourmalineCore.AspNetCore.JwtAuthentication.Identity")] -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests { - internal class LoginRequestModel + public class LoginRequestModel { public string Login { get; set; } diff --git a/JwtAuthentication.Core/Models/Request/LogoutRequestModel.cs b/JwtAuthentication.Shared/Models/Requests/LogoutRequestModel.cs similarity index 70% rename from JwtAuthentication.Core/Models/Request/LogoutRequestModel.cs rename to JwtAuthentication.Shared/Models/Requests/LogoutRequestModel.cs index a1eab96..fb576bf 100644 --- a/JwtAuthentication.Core/Models/Request/LogoutRequestModel.cs +++ b/JwtAuthentication.Shared/Models/Requests/LogoutRequestModel.cs @@ -3,9 +3,9 @@ [assembly: InternalsVisibleTo("TourmalineCore.AspNetCore.JwtAuthentication.Identity")] -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests { - internal class LogoutRequestModel + public class LogoutRequestModel { public Guid RefreshTokenValue { get; set; } diff --git a/JwtAuthentication.Core/Models/Request/RefreshTokenRequestModel.cs b/JwtAuthentication.Shared/Models/Requests/RefreshTokenRequestModel.cs similarity index 69% rename from JwtAuthentication.Core/Models/Request/RefreshTokenRequestModel.cs rename to JwtAuthentication.Shared/Models/Requests/RefreshTokenRequestModel.cs index cb65955..8a4ddb5 100644 --- a/JwtAuthentication.Core/Models/Request/RefreshTokenRequestModel.cs +++ b/JwtAuthentication.Shared/Models/Requests/RefreshTokenRequestModel.cs @@ -1,6 +1,6 @@ using System; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests { public class RefreshTokenRequestModel { diff --git a/JwtAuthentication.Core/Models/Request/RegistrationRequestModel.cs b/JwtAuthentication.Shared/Models/Requests/RegistrationRequestModel.cs similarity index 65% rename from JwtAuthentication.Core/Models/Request/RegistrationRequestModel.cs rename to JwtAuthentication.Shared/Models/Requests/RegistrationRequestModel.cs index ec1d97c..1444294 100644 --- a/JwtAuthentication.Core/Models/Request/RegistrationRequestModel.cs +++ b/JwtAuthentication.Shared/Models/Requests/RegistrationRequestModel.cs @@ -1,4 +1,4 @@ -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests { public class RegistrationRequestModel { diff --git a/JwtAuthentication.Shared/Models/Responses/AuthResponseModel.cs b/JwtAuthentication.Shared/Models/Responses/AuthResponseModel.cs new file mode 100644 index 0000000..c7a427e --- /dev/null +++ b/JwtAuthentication.Shared/Models/Responses/AuthResponseModel.cs @@ -0,0 +1,14 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("TourmalineCore.AspNetCore.JwtAuthentication.Identity")] +[assembly: InternalsVisibleTo("Tests")] + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses +{ + public class AuthResponseModel + { + public BaseTokenModel AccessToken { get; set; } + + public BaseTokenModel RefreshToken { get; set; } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Options/SharedAuthenticationOptions.cs b/JwtAuthentication.Shared/Options/BaseAuthenticationOptions.cs similarity index 93% rename from JwtAuthentication.Shared/Options/SharedAuthenticationOptions.cs rename to JwtAuthentication.Shared/Options/BaseAuthenticationOptions.cs index 577ba0c..03e6760 100644 --- a/JwtAuthentication.Shared/Options/SharedAuthenticationOptions.cs +++ b/JwtAuthentication.Shared/Options/BaseAuthenticationOptions.cs @@ -1,6 +1,6 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options { - public class SharedAuthenticationOptions + public class BaseAuthenticationOptions { private int _accessTokenExpireInMinutes; diff --git a/JwtAuthentication.Shared/Options/BaseCookieAuthOptions.cs b/JwtAuthentication.Shared/Options/BaseCookieAuthOptions.cs new file mode 100644 index 0000000..bc9a99e --- /dev/null +++ b/JwtAuthentication.Shared/Options/BaseCookieAuthOptions.cs @@ -0,0 +1,7 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options +{ + public class BaseCookieAuthOptions + { + public string Key { get; set; } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Options/BaseLoginEndpointOptions.cs b/JwtAuthentication.Shared/Options/BaseLoginEndpointOptions.cs new file mode 100644 index 0000000..56d5a21 --- /dev/null +++ b/JwtAuthentication.Shared/Options/BaseLoginEndpointOptions.cs @@ -0,0 +1,13 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options +{ + public class BaseLoginEndpointOptions + { + private string _loginEndpointRoute; + + public string LoginEndpointRoute + { + get => _loginEndpointRoute ?? "/auth/login"; + set => _loginEndpointRoute = value; + } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Options/RefreshEndpointOptions.cs b/JwtAuthentication.Shared/Options/BaseRefreshEndpointOptions.cs similarity index 87% rename from JwtAuthentication.Shared/Options/RefreshEndpointOptions.cs rename to JwtAuthentication.Shared/Options/BaseRefreshEndpointOptions.cs index 633ff80..26af474 100644 --- a/JwtAuthentication.Shared/Options/RefreshEndpointOptions.cs +++ b/JwtAuthentication.Shared/Options/BaseRefreshEndpointOptions.cs @@ -1,6 +1,6 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options { - public class RefreshEndpointOptions + public class BaseRefreshEndpointOptions { private string _refreshEndpointRoute; diff --git a/JwtAuthentication.Shared/Options/RefreshTokenOptions.cs b/JwtAuthentication.Shared/Options/BaseRefreshTokenOptions.cs similarity index 89% rename from JwtAuthentication.Shared/Options/RefreshTokenOptions.cs rename to JwtAuthentication.Shared/Options/BaseRefreshTokenOptions.cs index 398e80a..420bab2 100644 --- a/JwtAuthentication.Shared/Options/RefreshTokenOptions.cs +++ b/JwtAuthentication.Shared/Options/BaseRefreshTokenOptions.cs @@ -1,6 +1,6 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options { - public class RefreshTokenOptions + public class BaseRefreshTokenOptions { private int _refreshTokenExpireInMinutes; diff --git a/JwtAuthentication.Shared/Services/Contracts/ILoginService.cs b/JwtAuthentication.Shared/Services/Contracts/ILoginService.cs new file mode 100644 index 0000000..4414f41 --- /dev/null +++ b/JwtAuthentication.Shared/Services/Contracts/ILoginService.cs @@ -0,0 +1,14 @@ +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; + +[assembly: InternalsVisibleTo("TourmalineCore.AspNetCore.JwtAuthentication.Identity")] + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts +{ + public interface ILoginService + { + public Task LoginAsync(LoginRequestModel model); + } +} \ No newline at end of file diff --git a/JwtAuthentication.Core/Services/ILogoutService.cs b/JwtAuthentication.Shared/Services/Contracts/ILogoutService.cs similarity index 54% rename from JwtAuthentication.Core/Services/ILogoutService.cs rename to JwtAuthentication.Shared/Services/Contracts/ILogoutService.cs index d3d1d25..9809374 100644 --- a/JwtAuthentication.Core/Services/ILogoutService.cs +++ b/JwtAuthentication.Shared/Services/Contracts/ILogoutService.cs @@ -1,12 +1,12 @@ using System.Runtime.CompilerServices; using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; [assembly: InternalsVisibleTo("TourmalineCore.AspNetCore.JwtAuthentication.Identity")] -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts { - internal interface ILogoutService + public interface ILogoutService { public Task LogoutAsync(LogoutRequestModel model); } diff --git a/JwtAuthentication.Core/Services/IRefreshService.cs b/JwtAuthentication.Shared/Services/Contracts/IRefreshService.cs similarity index 60% rename from JwtAuthentication.Core/Services/IRefreshService.cs rename to JwtAuthentication.Shared/Services/Contracts/IRefreshService.cs index 1a5461c..76df4d3 100644 --- a/JwtAuthentication.Core/Services/IRefreshService.cs +++ b/JwtAuthentication.Shared/Services/Contracts/IRefreshService.cs @@ -1,13 +1,13 @@ using System; using System.Runtime.CompilerServices; using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; [assembly: InternalsVisibleTo("TourmalineCore.AspNetCore.JwtAuthentication.Identity")] -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts { - internal interface IRefreshService + public interface IRefreshService { public Task RefreshAsync(Guid refreshTokenValue, string clientFingerPrint); } diff --git a/JwtAuthentication.Core/Services/IRefreshTokenManager.cs b/JwtAuthentication.Shared/Services/Contracts/IRefreshTokenManager.cs similarity index 71% rename from JwtAuthentication.Core/Services/IRefreshTokenManager.cs rename to JwtAuthentication.Shared/Services/Contracts/IRefreshTokenManager.cs index c501a6a..71646b0 100644 --- a/JwtAuthentication.Core/Services/IRefreshTokenManager.cs +++ b/JwtAuthentication.Shared/Services/Contracts/IRefreshTokenManager.cs @@ -2,13 +2,13 @@ using System.Threading.Tasks; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts { - internal interface IRefreshTokenManager + public interface IRefreshTokenManager where TUser : class where TKey : IEquatable { - Task GenerateRefreshTokenAsync(object user, string clientFingerPrint); + Task GenerateRefreshTokenAsync(object user, string clientFingerPrint); Task GetRefreshTokenUserAsync(Guid refreshTokenValue, string clientFingerPrint); diff --git a/JwtAuthentication.Shared/Services/Contracts/IRegistrationService.cs b/JwtAuthentication.Shared/Services/Contracts/IRegistrationService.cs new file mode 100644 index 0000000..c93b48a --- /dev/null +++ b/JwtAuthentication.Shared/Services/Contracts/IRegistrationService.cs @@ -0,0 +1,14 @@ +using System; +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts +{ + public interface IRegistrationService + where TUser : class + where TRegistrationRequestModel : RegistrationRequestModel + { + Task RegisterAsync(TRegistrationRequestModel model, Func mapping); + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Services/Contracts/ICoreRefreshService.cs b/JwtAuthentication.Shared/Services/Contracts/ITokenManager.cs similarity index 62% rename from JwtAuthentication.Shared/Services/Contracts/ICoreRefreshService.cs rename to JwtAuthentication.Shared/Services/Contracts/ITokenManager.cs index 5e229f0..2e05c55 100644 --- a/JwtAuthentication.Shared/Services/Contracts/ICoreRefreshService.cs +++ b/JwtAuthentication.Shared/Services/Contracts/ITokenManager.cs @@ -3,8 +3,8 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts { - public interface ICoreRefreshService + public interface ITokenManager { - public Task RefreshAsync(string jwtRefreshToken); + Task GenerateAccessTokenAsync(string login = null); } -} +} \ No newline at end of file diff --git a/JwtAuthentication.Core/Services/Implementation/LoginService.cs b/JwtAuthentication.Shared/Services/LoginService.cs similarity index 69% rename from JwtAuthentication.Core/Services/Implementation/LoginService.cs rename to JwtAuthentication.Shared/Services/LoginService.cs index 752a4b5..99509eb 100644 --- a/JwtAuthentication.Core/Services/Implementation/LoginService.cs +++ b/JwtAuthentication.Shared/Services/LoginService.cs @@ -1,12 +1,13 @@ using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Errors; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services { - internal class LoginService : ILoginService + public class LoginService : ILoginService { private readonly ITokenManager _tokenManager; @@ -29,16 +30,16 @@ public virtual async Task LoginAsync(LoginRequestModel model) { AccessToken = await _tokenManager.GenerateAccessTokenAsync(model.Login) }; - } - - protected virtual async Task ValidateCredentials(LoginRequestModel model) - { + } + + protected virtual async Task ValidateCredentials(LoginRequestModel model) + { var isUserCredentialsValid = await _userCredentialsValidator.ValidateUserCredentials(model.Login, model.Password); if (!isUserCredentialsValid) - { + { throw new IncorrectLoginOrPasswordException(); - } + } } } } \ No newline at end of file diff --git a/JwtAuthentication.Core/Services/Implementation/TokenManager.cs b/JwtAuthentication.Shared/Services/TokenManager.cs similarity index 66% rename from JwtAuthentication.Core/Services/Implementation/TokenManager.cs rename to JwtAuthentication.Shared/Services/TokenManager.cs index 77d9b3b..72da1b6 100644 --- a/JwtAuthentication.Core/Services/Implementation/TokenManager.cs +++ b/JwtAuthentication.Shared/Services/TokenManager.cs @@ -2,23 +2,24 @@ using System.Runtime.CompilerServices; using System.Security.Claims; using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; [assembly: InternalsVisibleTo("TourmalineCore.AspNetCore.JwtAuthentication.Identity")] -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Implementation +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services { - internal class TokenManager : ITokenManager + public class TokenManager : ITokenManager { - private readonly AuthenticationOptions _options; + private readonly BaseAuthenticationOptions _options; private readonly IUserClaimsProvider _userClaimsProvider; private readonly IJwtTokenCreator _jwtTokenCreator; public TokenManager( - AuthenticationOptions options, + BaseAuthenticationOptions options, IUserClaimsProvider userClaimsProvider, IJwtTokenCreator jwtTokenCreator) { @@ -27,7 +28,7 @@ public TokenManager( _jwtTokenCreator = jwtTokenCreator; } - public async Task GenerateAccessTokenAsync(string login = null) + public async Task GenerateAccessTokenAsync(string login = null) { var claims = login == null ? new List() diff --git a/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenCreator.cs b/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenCreator.cs index 19a55a8..22e38b2 100644 --- a/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenCreator.cs +++ b/JwtAuthentication.Shared/TokenServices/Contracts/IJwtTokenCreator.cs @@ -7,6 +7,6 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contr { public interface IJwtTokenCreator { - Task CreateAsync(string tokenType, int tokenLifetimeInMinutes, List claims = null); + Task CreateAsync(string tokenType, int tokenLifetimeInMinutes, List claims = null); } } diff --git a/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs b/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs index 37bfd2d..a5a7be0 100644 --- a/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs +++ b/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs @@ -13,14 +13,14 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices { public class JwtTokenCreator : IJwtTokenCreator { - private readonly SharedAuthenticationOptions _authenticationOptions; + private readonly BaseAuthenticationOptions _authenticationOptions; - public JwtTokenCreator(SharedAuthenticationOptions authenticationOptions) + public JwtTokenCreator(BaseAuthenticationOptions authenticationOptions) { _authenticationOptions = authenticationOptions; } - public async Task CreateAsync(string tokenType, int tokenLifetimeInMinutes, List claims = null) + public async Task CreateAsync(string tokenType, int tokenLifetimeInMinutes, List claims = null) { if (!TokenType.IsAvailableTokenType(tokenType)) { @@ -48,7 +48,7 @@ public async Task CreateAsync(string tokenType, int tokenLifetimeInM expires: tokenExpiresIn, signingCredentials: GetCredentials()); - return await Task.FromResult(new TokenModel + return await Task.FromResult(new BaseTokenModel { Value = new JwtSecurityTokenHandler().WriteToken(token), ExpiresInUtc = tokenExpiresIn.ToUniversalTime(), diff --git a/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs b/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs index 10505f4..84b83b7 100644 --- a/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs +++ b/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs @@ -12,9 +12,9 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices { public class JwtTokenValidator : IJwtTokenValidator { - private readonly SharedAuthenticationOptions _authenticationOptions; + private readonly BaseAuthenticationOptions _authenticationOptions; - public JwtTokenValidator(SharedAuthenticationOptions options) + public JwtTokenValidator(BaseAuthenticationOptions options) { _authenticationOptions = options; } diff --git a/JwtAuthentication.Core/Contract/IUserClaimsProvider.cs b/JwtAuthentication.Shared/UserServices/Contracts/IUserClaimsProvider.cs similarity index 71% rename from JwtAuthentication.Core/Contract/IUserClaimsProvider.cs rename to JwtAuthentication.Shared/UserServices/Contracts/IUserClaimsProvider.cs index 715fe22..7d2dab4 100644 --- a/JwtAuthentication.Core/Contract/IUserClaimsProvider.cs +++ b/JwtAuthentication.Shared/UserServices/Contracts/IUserClaimsProvider.cs @@ -2,7 +2,7 @@ using System.Security.Claims; using System.Threading.Tasks; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts { public interface IUserClaimsProvider { diff --git a/JwtAuthentication.Core/Contract/IUserCredentialsValidator.cs b/JwtAuthentication.Shared/UserServices/Contracts/IUserCredentialsValidator.cs similarity index 66% rename from JwtAuthentication.Core/Contract/IUserCredentialsValidator.cs rename to JwtAuthentication.Shared/UserServices/Contracts/IUserCredentialsValidator.cs index a2959e8..d88a7ec 100644 --- a/JwtAuthentication.Core/Contract/IUserCredentialsValidator.cs +++ b/JwtAuthentication.Shared/UserServices/Contracts/IUserCredentialsValidator.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts { public interface IUserCredentialsValidator { diff --git a/JwtAuthentication.Core/Contract/Implementation/DefaultUserClaimsProvider.cs b/JwtAuthentication.Shared/UserServices/DefaultUserClaimsProvider.cs similarity index 63% rename from JwtAuthentication.Core/Contract/Implementation/DefaultUserClaimsProvider.cs rename to JwtAuthentication.Shared/UserServices/DefaultUserClaimsProvider.cs index 19a196d..90bf68b 100644 --- a/JwtAuthentication.Core/Contract/Implementation/DefaultUserClaimsProvider.cs +++ b/JwtAuthentication.Shared/UserServices/DefaultUserClaimsProvider.cs @@ -1,10 +1,11 @@ using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract.Implementation +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices { - internal class DefaultUserClaimsProvider : IUserClaimsProvider + public class DefaultUserClaimsProvider : IUserClaimsProvider { public Task> GetUserClaimsAsync(string login) { diff --git a/JwtAuthentication.Core/Contract/Implementation/FakeUserCredentialValidator.cs b/JwtAuthentication.Shared/UserServices/FakeUserCredentialValidator.cs similarity index 58% rename from JwtAuthentication.Core/Contract/Implementation/FakeUserCredentialValidator.cs rename to JwtAuthentication.Shared/UserServices/FakeUserCredentialValidator.cs index beaa503..82a03f5 100644 --- a/JwtAuthentication.Core/Contract/Implementation/FakeUserCredentialValidator.cs +++ b/JwtAuthentication.Shared/UserServices/FakeUserCredentialValidator.cs @@ -1,8 +1,9 @@ using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract.Implementation +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices { - internal class FakeUserCredentialValidator : IUserCredentialsValidator + public class FakeUserCredentialValidator : IUserCredentialsValidator { private const string Login = "Admin"; private const string Password = "Admin"; From ec55809504f3e03129ee1c9c8eccee568d078bb7 Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Mon, 29 Aug 2022 10:33:17 +0500 Subject: [PATCH 23/34] chore: #60: resolves a problem with login middleware registration --- .../Startup.cs | 49 +++ .../Properties/launchSettings.json | 56 ++-- .../ApplicationBuilderExtension.cs | 31 +- .../AuthenticationExtensions.cs | 47 +-- .../JwtAuthentication.Core.csproj | 14 +- .../Login/DefaultLoginMiddlewareBuilder.cs | 73 ----- .../Login/IDefaultLoginMiddlewareBuilder.cs | 17 -- .../Middlewares/Login/Models/LoginModel.cs | 16 +- .../ApplicationBuilderExtensions.cs | 2 +- .../Filters/RequiresPermission.cs | 6 + .../JwtAuthentication.Identity.csproj | 8 +- .../Middleware/Logout/LogoutMiddleware.cs | 6 +- .../Middleware/Refresh/RefreshMiddleware.cs | 9 +- .../IRegistrationMiddlewareBuilder.cs | 2 +- .../Registration/RegistrationMiddleware.cs | 12 +- .../RegistrationMiddlewareBuilder.cs | 2 +- .../Options/AuthenticationOptions.cs | 6 + .../Options/RefreshAuthenticationOptions.cs | 2 - .../Options/RefreshEndpointOptions.cs | 13 +- .../Options/RefreshOptions.cs | 2 +- .../Services/IdentityLoginService.cs | 11 +- .../Services/IdentityLogoutService.cs | 4 +- .../Services/IdentityRefreshLoginService.cs | 14 +- .../Services/IdentityRegistrationService.cs | 8 +- .../Services/RefreshSignInManager.cs | 6 +- .../Services/RefreshTokenManager.cs | 288 +++++++++--------- .../TourmalineAuthenticationBuilder.cs | 18 +- .../IdentityUserCredentialsValidator.cs | 10 +- .../Validators/RefreshTokenValidator.cs | 6 +- .../ApplicationBuilderExtension.cs | 127 ++++++++ .../AuthenticationExtensions.cs | 91 ++++++ .../Login/DefaultLoginMiddlewareBuilder.cs | 121 ++++++++ .../Middlewares/Login/LoginMiddleware.cs | 41 ++- .../LoginMiddlewareWithExecutedCallback.cs | 14 + .../LoginMiddlewareWithExecutingCallback.cs | 14 + .../Login/Models/BasicLoginModel.cs | 11 + .../Login/Models/IBasicLoginModel.cs | 11 + .../TokenHandlers/DebugTokenHandler.cs | 83 +++++ 38 files changed, 849 insertions(+), 402 deletions(-) delete mode 100644 JwtAuthentication.Core/Middlewares/Login/DefaultLoginMiddlewareBuilder.cs delete mode 100644 JwtAuthentication.Core/Middlewares/Login/IDefaultLoginMiddlewareBuilder.cs create mode 100644 JwtAuthentication.Identity/Filters/RequiresPermission.cs create mode 100644 JwtAuthentication.Identity/Options/AuthenticationOptions.cs create mode 100644 JwtAuthentication.Shared/ApplicationBuilderExtension.cs create mode 100644 JwtAuthentication.Shared/AuthenticationExtensions.cs create mode 100644 JwtAuthentication.Shared/Middlewares/Login/DefaultLoginMiddlewareBuilder.cs rename {JwtAuthentication.Core => JwtAuthentication.Shared}/Middlewares/Login/LoginMiddleware.cs (54%) create mode 100644 JwtAuthentication.Shared/Middlewares/Login/LoginMiddlewareWithExecutedCallback.cs create mode 100644 JwtAuthentication.Shared/Middlewares/Login/LoginMiddlewareWithExecutingCallback.cs create mode 100644 JwtAuthentication.Shared/Middlewares/Login/Models/BasicLoginModel.cs create mode 100644 JwtAuthentication.Shared/Middlewares/Login/Models/IBasicLoginModel.cs create mode 100644 JwtAuthentication.Shared/TokenHandlers/DebugTokenHandler.cs diff --git a/Examples/Example.NetCore3.1.BaseAuthentication/Startup.cs b/Examples/Example.NetCore3.1.BaseAuthentication/Startup.cs index 311bcdd..5d200b9 100644 --- a/Examples/Example.NetCore3.1.BaseAuthentication/Startup.cs +++ b/Examples/Example.NetCore3.1.BaseAuthentication/Startup.cs @@ -3,7 +3,11 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using System; +using System.Threading.Tasks; using TourmalineCore.AspNetCore.JwtAuthentication.Core; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; namespace Example.NetCore3._1.BaseAuthentication @@ -34,10 +38,55 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseRouting(); app + .OnLoginExecuting(OnLoginExecuting) + .OnLoginExecuted(OnLoginExecuted) .UseDefaultLoginMiddleware() .UseJwtAuthentication(); + //app + // .UseDefaultLoginMiddleware() + // .OnLoginExecuting(OnLoginExecuting) + // .OnLoginExecuted(OnLoginExecuted) + // .UseJwtAuthentication(); + + //app + // .OnLoginExecuting(OnLoginExecuting) + // .UseDefaultLoginMiddleware() + // .OnLoginExecuted(OnLoginExecuted) + // .UseJwtAuthentication(); + + //app + // .OnLoginExecuting(OnLoginExecuting) + // .OnLoginExecuted(OnLoginExecuted) + // .UseDefaultLoginMiddleware() + // .UseJwtAuthentication(); + + //app + // .OnLoginExecuted(OnLoginExecuted) + // .UseDefaultLoginMiddleware() + // .UseJwtAuthentication(); + + //app + // .OnLoginExecuting(OnLoginExecuting) + // .OnLoginExecuted(OnLoginExecuted); + + //app + // .UseDefaultLoginMiddleware() + // .UseJwtAuthentication(); + app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } + + private Task OnLoginExecuting(LoginModel data) + { + Console.WriteLine($"OnLoginExecuting: {data.Login}"); + return Task.CompletedTask; + } + + private Task OnLoginExecuted(LoginModel data) + { + Console.WriteLine($"OnLoginExecuted: {data.Login}"); + return Task.CompletedTask; + } } } \ No newline at end of file diff --git a/Examples/Example.NetCore5.0.RefreshTokenAuthAndRegistrationUsingIdentity/Properties/launchSettings.json b/Examples/Example.NetCore5.0.RefreshTokenAuthAndRegistrationUsingIdentity/Properties/launchSettings.json index b73f2cf..2cf93d5 100644 --- a/Examples/Example.NetCore5.0.RefreshTokenAuthAndRegistrationUsingIdentity/Properties/launchSettings.json +++ b/Examples/Example.NetCore5.0.RefreshTokenAuthAndRegistrationUsingIdentity/Properties/launchSettings.json @@ -1,28 +1,28 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:52216", - "sslPort": 44377 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "Example.NetCore5._0.RefreshTokenAuthAndRegistrationUsingIdentity": { - "commandName": "Project", - "dotnetRunMessages": "true", - "launchBrowser": true, - "applicationUrl": "https://localhost:5001;http://localhost:5000", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - } - } -} +{ + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:51742/", + "sslPort": 44384 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Example.NetCore5._0.RefreshTokenAuthAndRegistrationUsingIdentity": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "dotnetRunMessages": "true" + } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Core/ApplicationBuilderExtension.cs b/JwtAuthentication.Core/ApplicationBuilderExtension.cs index 66c06ef..4bdd5ff 100644 --- a/JwtAuthentication.Core/ApplicationBuilderExtension.cs +++ b/JwtAuthentication.Core/ApplicationBuilderExtension.cs @@ -2,11 +2,11 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login.Models; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core { @@ -31,11 +31,8 @@ public static IApplicationBuilder UseJwtAuthentication(this IApplicationBuilder /// /// public static IApplicationBuilder UseDefaultLoginMiddleware(this IApplicationBuilder applicationBuilder, LoginEndpointOptions loginEndpointOptions = null) - { - Func defaultOnLoginCallback = s => Task.CompletedTask; - - return applicationBuilder - .UseMiddleware(loginEndpointOptions ?? new LoginEndpointOptions(), defaultOnLoginCallback, defaultOnLoginCallback); + { + return Shared.ApplicationBuilderExtension.UseDefaultLoginMiddleware(applicationBuilder, loginEndpointOptions); } /// @@ -57,12 +54,11 @@ public static IApplicationBuilder UseCookieLoginMiddleware(this IApplicationBuil /// /// /// - public static IDefaultLoginMiddlewareBuilder OnLoginExecuting(this IApplicationBuilder applicationBuilder, Func callback) + public static IApplicationBuilder OnLoginExecuting(this IApplicationBuilder applicationBuilder, Func callback) { - return DefaultLoginMiddlewareBuilder - .GetInstance() - .SetAppBuilder(applicationBuilder) - .OnLoginExecuting(callback); + Func loginExecutingCallback = basicLoginModel => callback(LoginModel.MapFrom(basicLoginModel)); + + return Shared.ApplicationBuilderExtension.OnLoginExecuting(applicationBuilder, loginExecutingCallback); } /// @@ -71,12 +67,11 @@ public static IDefaultLoginMiddlewareBuilder OnLoginExecuting(this IApplicationB /// /// /// - public static IDefaultLoginMiddlewareBuilder OnLoginExecuted(this IApplicationBuilder applicationBuilder, Func callback) + public static IApplicationBuilder OnLoginExecuted(this IApplicationBuilder applicationBuilder, Func callback) { - return DefaultLoginMiddlewareBuilder - .GetInstance() - .SetAppBuilder(applicationBuilder) - .OnLoginExecuted(callback); + Func loginExecutedCallback = basicLoginModel => callback(LoginModel.MapFrom(basicLoginModel)); + + return Shared.ApplicationBuilderExtension.OnLoginExecuted(applicationBuilder, loginExecutedCallback); } /// @@ -91,8 +86,8 @@ public static IApplicationBuilder UseRefreshTokenMiddleware(this IApplicationBui return applicationBuilder .UseMiddleware(endpointOptions ?? new RefreshEndpointOptions(), defaultOnRefreshCallback, defaultOnRefreshCallback); - } - + } + /// /// Registering a callback function to perform actions when when the refresh starts. /// diff --git a/JwtAuthentication.Core/AuthenticationExtensions.cs b/JwtAuthentication.Core/AuthenticationExtensions.cs index 4243830..174e4ad 100644 --- a/JwtAuthentication.Core/AuthenticationExtensions.cs +++ b/JwtAuthentication.Core/AuthenticationExtensions.cs @@ -6,7 +6,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Filters; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Core.TokenHandlers; @@ -16,7 +16,6 @@ using AuthenticationOptions = TourmalineCore.AspNetCore.JwtAuthentication.Core.Options.AuthenticationOptions; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core @@ -48,15 +47,17 @@ public static IServiceCollection AddJwtAuthentication( this IServiceCollection services, AuthenticationOptions authenticationOptions) { - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); + return Shared.AuthenticationExtensions.AddJwtAuthentication(services, authenticationOptions); - services.AddJwtBearer(authenticationOptions); + //services.AddTransient(); + //services.AddTransient(); + //services.AddTransient(); + //services.AddTransient(); + //services.AddTransient(); - return services; + //services.AddJwtBearer(authenticationOptions); + + //return services; } /// @@ -86,20 +87,20 @@ public static IServiceCollection WithUserClaimsProvider( RequiresPermission.ClaimType = permissionClaimTypeKey; return services.AddTransient(typeof(IUserClaimsProvider), typeof(TUserClaimsProvider)); - } - - public static IServiceCollection AddLoginWithRefresh( - this IServiceCollection services, - RefreshTokenOptions refreshTokenOptions = null) - { - services.AddSingleton(refreshTokenOptions ?? new RefreshTokenOptions()); - - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - - return services; + } + + public static IServiceCollection AddLoginWithRefresh( + this IServiceCollection services, + RefreshTokenOptions refreshTokenOptions = null) + { + services.AddSingleton(refreshTokenOptions ?? new RefreshTokenOptions()); + + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + return services; } internal static void AddJwtBearer( diff --git a/JwtAuthentication.Core/JwtAuthentication.Core.csproj b/JwtAuthentication.Core/JwtAuthentication.Core.csproj index fd3ab6f..e3f96cf 100644 --- a/JwtAuthentication.Core/JwtAuthentication.Core.csproj +++ b/JwtAuthentication.Core/JwtAuthentication.Core.csproj @@ -3,7 +3,7 @@ netcoreapp3.1;net5.0;net6.0 TourmalineCore.AspNetCore.JwtAuthentication.Core - 0.3.4-alpha.2 + 0.3.4-alpha.7 Koval Maxim, Nikita Medvedev, Aleksandr Shinkarev Tourmaline Core JwtAuthentication @@ -33,7 +33,7 @@ - @@ -44,12 +44,12 @@ - - - - - + + + true + JwtAuthentication.Shared.dll + diff --git a/JwtAuthentication.Core/Middlewares/Login/DefaultLoginMiddlewareBuilder.cs b/JwtAuthentication.Core/Middlewares/Login/DefaultLoginMiddlewareBuilder.cs deleted file mode 100644 index 993eb20..0000000 --- a/JwtAuthentication.Core/Middlewares/Login/DefaultLoginMiddlewareBuilder.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login -{ - public class DefaultLoginMiddlewareBuilder : IDefaultLoginMiddlewareBuilder - { - private static Func _onLoginExecutingCallback = s => Task.CompletedTask; - private static Func _onLoginExecutedCallback = s => Task.CompletedTask; - - private IApplicationBuilder _applicationBuilder; - - private static DefaultLoginMiddlewareBuilder _instance; - - private DefaultLoginMiddlewareBuilder() - { - } - - internal static DefaultLoginMiddlewareBuilder GetInstance() - { - if (_instance != null) - { - return _instance; - } - - _instance = new DefaultLoginMiddlewareBuilder(); - - return _instance; - } - - internal IDefaultLoginMiddlewareBuilder SetAppBuilder(IApplicationBuilder applicationBuilder) - { - _applicationBuilder = applicationBuilder; - return this; - } - - /// - /// Registering a callback function to perform actions when when the authentication starts. - /// - /// - /// - public IDefaultLoginMiddlewareBuilder OnLoginExecuting(Func callback) - { - _onLoginExecutingCallback = callback; - return this; - } - - /// - /// Registering a callback function to perform actions when the authentication ends. - /// - /// - /// - public IDefaultLoginMiddlewareBuilder OnLoginExecuted(Func callback) - { - _onLoginExecutedCallback = callback; - return this; - } - - /// - /// Adds middleware to handle incoming login requests. - /// - /// - /// - public IApplicationBuilder UseDefaultLoginMiddleware(LoginEndpointOptions loginEndpointOptions = null) - { - return _applicationBuilder - .UseMiddleware(loginEndpointOptions ?? new LoginEndpointOptions(), _onLoginExecutingCallback, _onLoginExecutedCallback); - } - } -} \ No newline at end of file diff --git a/JwtAuthentication.Core/Middlewares/Login/IDefaultLoginMiddlewareBuilder.cs b/JwtAuthentication.Core/Middlewares/Login/IDefaultLoginMiddlewareBuilder.cs deleted file mode 100644 index 58b90bd..0000000 --- a/JwtAuthentication.Core/Middlewares/Login/IDefaultLoginMiddlewareBuilder.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login -{ - public interface IDefaultLoginMiddlewareBuilder - { - public IDefaultLoginMiddlewareBuilder OnLoginExecuting(Func callback); - - public IDefaultLoginMiddlewareBuilder OnLoginExecuted(Func callback); - - public IApplicationBuilder UseDefaultLoginMiddleware(LoginEndpointOptions loginEndpointOptions = null); - } -} \ No newline at end of file diff --git a/JwtAuthentication.Core/Middlewares/Login/Models/LoginModel.cs b/JwtAuthentication.Core/Middlewares/Login/Models/LoginModel.cs index 12a6725..0e9c17b 100644 --- a/JwtAuthentication.Core/Middlewares/Login/Models/LoginModel.cs +++ b/JwtAuthentication.Core/Middlewares/Login/Models/LoginModel.cs @@ -1,11 +1,21 @@ +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login.Models; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models { - public class LoginModel + public class LoginModel : IBasicLoginModel { public string Login { get; set; } - public string Password { get; set; } - public string ClientFingerPrint { get; set; } + + public static LoginModel MapFrom(BasicLoginModel basicLoginModel) + { + return new LoginModel + { + Login = basicLoginModel.Login, + Password = basicLoginModel.Password, + ClientFingerPrint = basicLoginModel.ClientFingerPrint + }; + } } } \ No newline at end of file diff --git a/JwtAuthentication.Identity/ApplicationBuilderExtensions.cs b/JwtAuthentication.Identity/ApplicationBuilderExtensions.cs index 4275058..f22a088 100644 --- a/JwtAuthentication.Identity/ApplicationBuilderExtensions.cs +++ b/JwtAuthentication.Identity/ApplicationBuilderExtensions.cs @@ -3,12 +3,12 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Logout; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Logout.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Registration; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Registration.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity { diff --git a/JwtAuthentication.Identity/Filters/RequiresPermission.cs b/JwtAuthentication.Identity/Filters/RequiresPermission.cs new file mode 100644 index 0000000..7523a88 --- /dev/null +++ b/JwtAuthentication.Identity/Filters/RequiresPermission.cs @@ -0,0 +1,6 @@ +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Filters; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Filters +{ + public class RequiresPermission : BaseRequiresPermission { } +} \ No newline at end of file diff --git a/JwtAuthentication.Identity/JwtAuthentication.Identity.csproj b/JwtAuthentication.Identity/JwtAuthentication.Identity.csproj index 945e9f1..89a63dd 100644 --- a/JwtAuthentication.Identity/JwtAuthentication.Identity.csproj +++ b/JwtAuthentication.Identity/JwtAuthentication.Identity.csproj @@ -26,12 +26,8 @@ - - - - - - + + diff --git a/JwtAuthentication.Identity/Middleware/Logout/LogoutMiddleware.cs b/JwtAuthentication.Identity/Middleware/Logout/LogoutMiddleware.cs index b93f52d..b5ccea9 100644 --- a/JwtAuthentication.Identity/Middleware/Logout/LogoutMiddleware.cs +++ b/JwtAuthentication.Identity/Middleware/Logout/LogoutMiddleware.cs @@ -2,11 +2,11 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Logout.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Logout { diff --git a/JwtAuthentication.Identity/Middleware/Refresh/RefreshMiddleware.cs b/JwtAuthentication.Identity/Middleware/Refresh/RefreshMiddleware.cs index 6ac9778..a037682 100644 --- a/JwtAuthentication.Identity/Middleware/Refresh/RefreshMiddleware.cs +++ b/JwtAuthentication.Identity/Middleware/Refresh/RefreshMiddleware.cs @@ -2,13 +2,12 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Refresh.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Refresh { diff --git a/JwtAuthentication.Identity/Middleware/Registration/IRegistrationMiddlewareBuilder.cs b/JwtAuthentication.Identity/Middleware/Registration/IRegistrationMiddlewareBuilder.cs index e729ad7..fbae330 100644 --- a/JwtAuthentication.Identity/Middleware/Registration/IRegistrationMiddlewareBuilder.cs +++ b/JwtAuthentication.Identity/Middleware/Registration/IRegistrationMiddlewareBuilder.cs @@ -2,9 +2,9 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Identity; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Registration.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Registration { diff --git a/JwtAuthentication.Identity/Middleware/Registration/RegistrationMiddleware.cs b/JwtAuthentication.Identity/Middleware/Registration/RegistrationMiddleware.cs index c6a4b93..35727c5 100644 --- a/JwtAuthentication.Identity/Middleware/Registration/RegistrationMiddleware.cs +++ b/JwtAuthentication.Identity/Middleware/Registration/RegistrationMiddleware.cs @@ -3,14 +3,14 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Registration.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options; - +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Errors; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Registration { internal class RegistrationMiddleware : RegistrationMiddleware diff --git a/JwtAuthentication.Identity/Middleware/Registration/RegistrationMiddlewareBuilder.cs b/JwtAuthentication.Identity/Middleware/Registration/RegistrationMiddlewareBuilder.cs index 6ab5a60..d0624a0 100644 --- a/JwtAuthentication.Identity/Middleware/Registration/RegistrationMiddlewareBuilder.cs +++ b/JwtAuthentication.Identity/Middleware/Registration/RegistrationMiddlewareBuilder.cs @@ -2,9 +2,9 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Identity; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Registration.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Middleware.Registration { diff --git a/JwtAuthentication.Identity/Options/AuthenticationOptions.cs b/JwtAuthentication.Identity/Options/AuthenticationOptions.cs new file mode 100644 index 0000000..d8354cb --- /dev/null +++ b/JwtAuthentication.Identity/Options/AuthenticationOptions.cs @@ -0,0 +1,6 @@ +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options +{ + public class AuthenticationOptions : BaseAuthenticationOptions { } +} \ No newline at end of file diff --git a/JwtAuthentication.Identity/Options/RefreshAuthenticationOptions.cs b/JwtAuthentication.Identity/Options/RefreshAuthenticationOptions.cs index 69b17b4..1ebc6db 100644 --- a/JwtAuthentication.Identity/Options/RefreshAuthenticationOptions.cs +++ b/JwtAuthentication.Identity/Options/RefreshAuthenticationOptions.cs @@ -1,5 +1,3 @@ -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; - namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options { public class RefreshAuthenticationOptions : AuthenticationOptions diff --git a/JwtAuthentication.Identity/Options/RefreshEndpointOptions.cs b/JwtAuthentication.Identity/Options/RefreshEndpointOptions.cs index ba87c67..e4b4cf8 100644 --- a/JwtAuthentication.Identity/Options/RefreshEndpointOptions.cs +++ b/JwtAuthentication.Identity/Options/RefreshEndpointOptions.cs @@ -1,13 +1,6 @@ +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options { - public class RefreshEndpointOptions - { - private string _refreshEndpointRoute; - - public string RefreshEndpointRoute - { - get => _refreshEndpointRoute ?? "/auth/refresh"; - set => _refreshEndpointRoute = value; - } - } + public class RefreshEndpointOptions : BaseRefreshEndpointOptions { } } \ No newline at end of file diff --git a/JwtAuthentication.Identity/Options/RefreshOptions.cs b/JwtAuthentication.Identity/Options/RefreshOptions.cs index 7873cc2..afe2a4d 100644 --- a/JwtAuthentication.Identity/Options/RefreshOptions.cs +++ b/JwtAuthentication.Identity/Options/RefreshOptions.cs @@ -14,7 +14,7 @@ public int RefreshConfidenceIntervalInMilliseconds if (value <= 0) { throw new ArgumentException("Refresh confidence interval cannot be zero or negative"); - } + } _refreshConfidenceIntervalInMilliseconds = value; } diff --git a/JwtAuthentication.Identity/Services/IdentityLoginService.cs b/JwtAuthentication.Identity/Services/IdentityLoginService.cs index 8181ab2..f020b9b 100644 --- a/JwtAuthentication.Identity/Services/IdentityLoginService.cs +++ b/JwtAuthentication.Identity/Services/IdentityLoginService.cs @@ -1,12 +1,11 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Errors; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Services { @@ -54,7 +53,7 @@ public async Task LoginAsync(LoginRequestModel model) return new AuthResponseModel { - AccessToken = new TokenModel + AccessToken = new BaseTokenModel { Value = token.Value, ExpiresInUtc = token.ExpiresInUtc, diff --git a/JwtAuthentication.Identity/Services/IdentityLogoutService.cs b/JwtAuthentication.Identity/Services/IdentityLogoutService.cs index 675b117..9b0f720 100644 --- a/JwtAuthentication.Identity/Services/IdentityLogoutService.cs +++ b/JwtAuthentication.Identity/Services/IdentityLogoutService.cs @@ -1,8 +1,8 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Services { diff --git a/JwtAuthentication.Identity/Services/IdentityRefreshLoginService.cs b/JwtAuthentication.Identity/Services/IdentityRefreshLoginService.cs index dabd63f..9b778ae 100644 --- a/JwtAuthentication.Identity/Services/IdentityRefreshLoginService.cs +++ b/JwtAuthentication.Identity/Services/IdentityRefreshLoginService.cs @@ -1,13 +1,13 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Validators; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Errors; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Services { @@ -100,8 +100,8 @@ private async Task GenerateAuthTokensWhenRefreshConfidenceInt if (refreshTokenIsInConfidenceInterval) { return await _signInManager.GenerateAuthTokens(user, clientFingerPrint); - } - + } + throw new RefreshTokenIsNotInConfidenceIntervalException(); } } diff --git a/JwtAuthentication.Identity/Services/IdentityRegistrationService.cs b/JwtAuthentication.Identity/Services/IdentityRegistrationService.cs index 3c78fa8..34e7890 100644 --- a/JwtAuthentication.Identity/Services/IdentityRegistrationService.cs +++ b/JwtAuthentication.Identity/Services/IdentityRegistrationService.cs @@ -1,10 +1,10 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Errors; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Services { diff --git a/JwtAuthentication.Identity/Services/RefreshSignInManager.cs b/JwtAuthentication.Identity/Services/RefreshSignInManager.cs index b386cb1..0bca62a 100644 --- a/JwtAuthentication.Identity/Services/RefreshSignInManager.cs +++ b/JwtAuthentication.Identity/Services/RefreshSignInManager.cs @@ -7,9 +7,9 @@ using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Response; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; - +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Services { internal class RefreshSignInManager : RefreshSignInManager where TUser : IdentityUser diff --git a/JwtAuthentication.Identity/Services/RefreshTokenManager.cs b/JwtAuthentication.Identity/Services/RefreshTokenManager.cs index 35d1927..e6dd9d5 100644 --- a/JwtAuthentication.Identity/Services/RefreshTokenManager.cs +++ b/JwtAuthentication.Identity/Services/RefreshTokenManager.cs @@ -1,147 +1,147 @@ -using System; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; -using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options; +using System; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Errors; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; -[assembly: InternalsVisibleTo("Tests")] - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Services -{ - internal class RefreshTokenManager : RefreshTokenManager where TUser : IdentityUser - { - public RefreshTokenManager( - TourmalineDbContext dbContext, - RefreshAuthenticationOptions options) - :base(dbContext, options) - { - } - } - - internal class RefreshTokenManager : IRefreshTokenManager - where TUser : IdentityUser - where TKey : IEquatable - { - private readonly TourmalineDbContext _dbContext; - private readonly RefreshAuthenticationOptions _options; - - public RefreshTokenManager( - TourmalineDbContext dbContext, - RefreshAuthenticationOptions options) - { - _dbContext = dbContext; - _options = options; - } - - public async Task GenerateRefreshTokenAsync(object user, string clientFingerPrint) - { - var refreshToken = CreateRefreshToken(user, clientFingerPrint); - - _dbContext.Attach(refreshToken.User); - await _dbContext.Set>().AddAsync(refreshToken); - await _dbContext.SaveChangesAsync(); - - return BuildTokenModelByRefreshToken(refreshToken); - } - - public async Task GetRefreshTokenUserAsync(Guid refreshTokenValue, string clientFingerPrint) - { - var token = await _dbContext - .Set>() - .AsQueryable() - .AsNoTracking() - .Include(x => x.User) - .FirstOrDefaultAsync(x => x.Value == refreshTokenValue - && x.ExpiresIn > DateTime.UtcNow - && (clientFingerPrint == null || x.ClientFingerPrint == clientFingerPrint)); - - ThrowExceptionIfTokenIsNull(token); - - return token.User; - } - - public async Task IsTokenActiveAsync(TKey userId, Guid refreshTokenValue) - { - var token = await GetRefreshTokenAsync(userId, refreshTokenValue); - - return token.IsActive; - } - - public async Task InvalidateRefreshTokenAsync(TKey userId, Guid refreshTokenValue) - { - var token = await _dbContext - .Set>() - .Include(x => x.User) - .AsQueryable() - .FirstOrDefaultAsync(x => x.Value == refreshTokenValue - && x.IsActive - && x.UserId.Equals(userId)); - - ThrowExceptionIfTokenIsNull(token); - - token.Expire(); - - await _dbContext.SaveChangesAsync(); - } - - public async Task IsRefreshTokenInConfidenceIntervalAsync(TKey userId, Guid refreshTokenValue, int refreshConfidenceIntervalInMilliseconds) - { - var token = await GetRefreshTokenAsync(userId, refreshTokenValue); - - return (DateTime.UtcNow - token.ExpiredAtUtc).TotalMilliseconds <= refreshConfidenceIntervalInMilliseconds; - } - - private async Task> GetRefreshTokenAsync(TKey userId, Guid refreshTokenValue) - { - var token = await _dbContext - .Set>() - .Include(x => x.User) - .AsQueryable() - .AsNoTracking() - .FirstOrDefaultAsync(x => x.Value == refreshTokenValue && x.UserId.Equals(userId)); - - ThrowExceptionIfTokenIsNull(token); - - return token; - } - - private RefreshToken CreateRefreshToken(object user, string clientFingerPrint) - { - var expiresDate = DateTime.UtcNow.AddMinutes(_options.RefreshTokenExpireInMinutes); - - var newToken = new RefreshToken - { - Value = Guid.NewGuid(), - ExpiresIn = expiresDate, - IsActive = true, - ClientFingerPrint = clientFingerPrint, - User = (TUser)user, - }; - - return newToken; - } - - private static BaseTokenModel BuildTokenModelByRefreshToken(RefreshToken refreshToken) - { - return new BaseTokenModel - { - Value = refreshToken.Value.ToString(), - ExpiresInUtc = refreshToken.ExpiresIn.ToUniversalTime(), - }; - } - - private static void ThrowExceptionIfTokenIsNull(RefreshToken token) - { - if (token == null) - { - throw new RefreshTokenNotFoundException(); - } - } - } +[assembly: InternalsVisibleTo("Tests")] + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Services +{ + internal class RefreshTokenManager : RefreshTokenManager where TUser : IdentityUser + { + public RefreshTokenManager( + TourmalineDbContext dbContext, + RefreshAuthenticationOptions options) + :base(dbContext, options) + { + } + } + + internal class RefreshTokenManager : IRefreshTokenManager + where TUser : IdentityUser + where TKey : IEquatable + { + private readonly TourmalineDbContext _dbContext; + private readonly RefreshAuthenticationOptions _options; + + public RefreshTokenManager( + TourmalineDbContext dbContext, + RefreshAuthenticationOptions options) + { + _dbContext = dbContext; + _options = options; + } + + public async Task GenerateRefreshTokenAsync(object user, string clientFingerPrint) + { + var refreshToken = CreateRefreshToken(user, clientFingerPrint); + + _dbContext.Attach(refreshToken.User); + await _dbContext.Set>().AddAsync(refreshToken); + await _dbContext.SaveChangesAsync(); + + return BuildTokenModelByRefreshToken(refreshToken); + } + + public async Task GetRefreshTokenUserAsync(Guid refreshTokenValue, string clientFingerPrint) + { + var token = await _dbContext + .Set>() + .AsQueryable() + .AsNoTracking() + .Include(x => x.User) + .FirstOrDefaultAsync(x => x.Value == refreshTokenValue + && x.ExpiresIn > DateTime.UtcNow + && (clientFingerPrint == null || x.ClientFingerPrint == clientFingerPrint)); + + ThrowExceptionIfTokenIsNull(token); + + return token.User; + } + + public async Task IsTokenActiveAsync(TKey userId, Guid refreshTokenValue) + { + var token = await GetRefreshTokenAsync(userId, refreshTokenValue); + + return token.IsActive; + } + + public async Task InvalidateRefreshTokenAsync(TKey userId, Guid refreshTokenValue) + { + var token = await _dbContext + .Set>() + .Include(x => x.User) + .AsQueryable() + .FirstOrDefaultAsync(x => x.Value == refreshTokenValue + && x.IsActive + && x.UserId.Equals(userId)); + + ThrowExceptionIfTokenIsNull(token); + + token.Expire(); + + await _dbContext.SaveChangesAsync(); + } + + public async Task IsRefreshTokenInConfidenceIntervalAsync(TKey userId, Guid refreshTokenValue, int refreshConfidenceIntervalInMilliseconds) + { + var token = await GetRefreshTokenAsync(userId, refreshTokenValue); + + return (DateTime.UtcNow - token.ExpiredAtUtc).TotalMilliseconds <= refreshConfidenceIntervalInMilliseconds; + } + + private async Task> GetRefreshTokenAsync(TKey userId, Guid refreshTokenValue) + { + var token = await _dbContext + .Set>() + .Include(x => x.User) + .AsQueryable() + .AsNoTracking() + .FirstOrDefaultAsync(x => x.Value == refreshTokenValue && x.UserId.Equals(userId)); + + ThrowExceptionIfTokenIsNull(token); + + return token; + } + + private RefreshToken CreateRefreshToken(object user, string clientFingerPrint) + { + var expiresDate = DateTime.UtcNow.AddMinutes(_options.RefreshTokenExpireInMinutes); + + var newToken = new RefreshToken + { + Value = Guid.NewGuid(), + ExpiresIn = expiresDate, + IsActive = true, + ClientFingerPrint = clientFingerPrint, + User = (TUser)user, + }; + + return newToken; + } + + private static BaseTokenModel BuildTokenModelByRefreshToken(RefreshToken refreshToken) + { + return new BaseTokenModel + { + Value = refreshToken.Value.ToString(), + ExpiresInUtc = refreshToken.ExpiresIn.ToUniversalTime(), + }; + } + + private static void ThrowExceptionIfTokenIsNull(RefreshToken token) + { + if (token == null) + { + throw new RefreshTokenNotFoundException(); + } + } + } } \ No newline at end of file diff --git a/JwtAuthentication.Identity/TourmalineAuthenticationBuilder.cs b/JwtAuthentication.Identity/TourmalineAuthenticationBuilder.cs index c336cbe..a4c4fb4 100644 --- a/JwtAuthentication.Identity/TourmalineAuthenticationBuilder.cs +++ b/JwtAuthentication.Identity/TourmalineAuthenticationBuilder.cs @@ -1,18 +1,16 @@ using System; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.DependencyInjection; -using TourmalineCore.AspNetCore.JwtAuthentication.Core; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract.Implementation; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Filters; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Validators; - +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; +using TourmalineCore.AspNetCore.JwtAuthentication.Identity.Filters; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity { public class TourmalineAuthenticationBuilder : TourmalineAuthenticationBuilder @@ -204,8 +202,8 @@ private void AddJwt( IServiceCollection services, AuthenticationOptions authenticationOptions = null) { - var options = authenticationOptions ?? new RefreshAuthenticationOptions(); - services.AddJwtBearer(options); + var options = authenticationOptions ?? new RefreshAuthenticationOptions(); + Shared.AuthenticationExtensions.AddJwtBearer(services, options); } } } \ No newline at end of file diff --git a/JwtAuthentication.Identity/Validators/IdentityUserCredentialsValidator.cs b/JwtAuthentication.Identity/Validators/IdentityUserCredentialsValidator.cs index 82dc4ea..823bdfd 100644 --- a/JwtAuthentication.Identity/Validators/IdentityUserCredentialsValidator.cs +++ b/JwtAuthentication.Identity/Validators/IdentityUserCredentialsValidator.cs @@ -1,21 +1,21 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contract; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Validators { - internal class IdentityUserCredentialsValidator : IdentityUserCredentialsValidator + internal class IdentityUserCredentialsValidator : IdentityUserCredentialsValidator where TUser : IdentityUser { public IdentityUserCredentialsValidator(SignInManager signInManager) : base(signInManager) { } - } + } - internal class IdentityUserCredentialsValidator : IUserCredentialsValidator - where TUser : IdentityUser + internal class IdentityUserCredentialsValidator : IUserCredentialsValidator + where TUser : IdentityUser where TKey : IEquatable { private readonly SignInManager _signInManager; diff --git a/JwtAuthentication.Identity/Validators/RefreshTokenValidator.cs b/JwtAuthentication.Identity/Validators/RefreshTokenValidator.cs index 29f4a4d..c7eba5f 100644 --- a/JwtAuthentication.Identity/Validators/RefreshTokenValidator.cs +++ b/JwtAuthentication.Identity/Validators/RefreshTokenValidator.cs @@ -1,6 +1,6 @@ using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.ErrorHandling; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Request; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Errors; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Validators { @@ -14,7 +14,7 @@ public Task ValidateAsync(RefreshTokenRequestModel model) private void InternalValidate(RefreshTokenRequestModel model) { if (model == null || model.RefreshTokenValue == default) - { + { throw new RefreshTokenOrFingerprintNotFoundException(); } } diff --git a/JwtAuthentication.Shared/ApplicationBuilderExtension.cs b/JwtAuthentication.Shared/ApplicationBuilderExtension.cs new file mode 100644 index 0000000..d6a5e13 --- /dev/null +++ b/JwtAuthentication.Shared/ApplicationBuilderExtension.cs @@ -0,0 +1,127 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared +{ + public static class ApplicationBuilderExtension + { + /// + /// Adds Authentication and Authorization to the app. + /// + /// + /// + public static IApplicationBuilder UseJwtAuthentication(this IApplicationBuilder applicationBuilder) + { + return applicationBuilder + .UseAuthentication() + .UseAuthorization(); + } + + /// + /// Adds middleware to handle incoming login requests. + /// + /// + /// + /// + public static IApplicationBuilder UseDefaultLoginMiddleware(this IApplicationBuilder applicationBuilder, BaseLoginEndpointOptions loginEndpointOptions = null) + { + return DefaultLoginMiddlewareBuilder + .GetInstance() + .SetAppBuilder(applicationBuilder) + .SetLoginEndpointOptions(loginEndpointOptions) + .UseDefaultLoginMiddleware(); + + //Func defaultOnLoginCallback = s => Task.CompletedTask; + + //return applicationBuilder + // .UseMiddleware(loginEndpointOptions ?? new BaseLoginEndpointOptions(), defaultOnLoginCallback, defaultOnLoginCallback); + } + + ///// + ///// Adds middleware to handle incoming login requests using cookies to store auth token. + ///// + ///// + ///// + ///// + //public static IApplicationBuilder UseCookieLoginMiddleware(this IApplicationBuilder applicationBuilder, CookieAuthOptions options, LoginEndpointOptions loginEndpointOptions = null) + //{ + // return applicationBuilder + // .UseMiddleware(options, loginEndpointOptions ?? new LoginEndpointOptions()) + // .UseMiddleware(options); + //} + + /// + /// Registering a callback function to perform actions when when the authentication starts. + /// + /// + /// + /// + public static IApplicationBuilder OnLoginExecuting(this IApplicationBuilder applicationBuilder, Func callback) + { + return DefaultLoginMiddlewareBuilder + .GetInstance() + .SetAppBuilder(applicationBuilder) + .OnLoginExecuting(callback); + } + + /// + /// Registering a callback function to perform actions when the authentication ends. + /// + /// + /// + /// + public static IApplicationBuilder OnLoginExecuted(this IApplicationBuilder applicationBuilder, Func callback) + { + return DefaultLoginMiddlewareBuilder + .GetInstance() + .SetAppBuilder(applicationBuilder) + .OnLoginExecuted(callback); + } + + ///// + ///// Adds middleware to handle incoming login and token refresh requests. + ///// + ///// + ///// + ///// + //public static IApplicationBuilder UseRefreshTokenMiddleware(this IApplicationBuilder applicationBuilder, RefreshEndpointOptions endpointOptions = null) + //{ + // Func defaultOnRefreshCallback = s => Task.CompletedTask; + + // return applicationBuilder + // .UseMiddleware(endpointOptions ?? new RefreshEndpointOptions(), defaultOnRefreshCallback, defaultOnRefreshCallback); + //} + + ///// + ///// Registering a callback function to perform actions when when the refresh starts. + ///// + ///// + ///// + ///// + //public static IRefreshMiddlewareBuilder OnRefreshExecuting(this IApplicationBuilder applicationBuilder, Func callback) + //{ + // return RefreshMiddlewareBuilder + // .GetInstance() + // .SetAppBuilder(applicationBuilder) + // .OnRefreshExecuting(callback); + //} + + ///// + ///// Registering a callback function to perform actions when the refresh ends. + ///// + ///// + ///// + ///// + //public static IRefreshMiddlewareBuilder OnRefreshExecuted(this IApplicationBuilder applicationBuilder, Func callback) + //{ + // return RefreshMiddlewareBuilder + // .GetInstance() + // .SetAppBuilder(applicationBuilder) + // .OnRefreshExecuted(callback); + //} + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/AuthenticationExtensions.cs b/JwtAuthentication.Shared/AuthenticationExtensions.cs new file mode 100644 index 0000000..6b8cd82 --- /dev/null +++ b/JwtAuthentication.Shared/AuthenticationExtensions.cs @@ -0,0 +1,91 @@ +using System; +using System.IdentityModel.Tokens.Jwt; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.IdentityModel.Tokens; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Signing; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenHandlers; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared +{ + public static class AuthenticationExtensions + { + /// + /// Adds the ability to use the basic functionality of JWT + /// + /// + /// + /// + public static IServiceCollection AddJwtAuthentication( + this IServiceCollection services, + BaseAuthenticationOptions authenticationOptions) + { + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + services.AddJwtBearer(authenticationOptions); + + return services; + } + + public static void AddJwtBearer( + this IServiceCollection services, + BaseAuthenticationOptions authenticationOptions) + { + services.AddSingleton(authenticationOptions); + + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); + + Func schemeSelector = context => null; + + var authBuilder = services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme); + + if (authenticationOptions.IsDebugTokenEnabled) + { + authBuilder.AddScheme(DebugTokenHandler.Schema, + options => { } + ); + + schemeSelector = context => + { + string debugHeader = context.Request.Headers[DebugTokenHandler.HeaderName]; + + return string.IsNullOrWhiteSpace(debugHeader) == false + ? DebugTokenHandler.Schema + : null; + }; + } + + authBuilder + .AddJwtBearer( + options => + { + options.TokenValidationParameters = new TokenValidationParameters + { + ValidateLifetime = true, + ValidateIssuer = false, + ValidateAudience = false, + ValidateIssuerSigningKey = true, + IssuerSigningKey = SigningHelper.GetPublicKey(authenticationOptions.PublicSigningKey), + ClockSkew = TimeSpan.Zero, + }; + + options.ForwardDefaultSelector = schemeSelector; + } + ); + } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Middlewares/Login/DefaultLoginMiddlewareBuilder.cs b/JwtAuthentication.Shared/Middlewares/Login/DefaultLoginMiddlewareBuilder.cs new file mode 100644 index 0000000..eeab7e6 --- /dev/null +++ b/JwtAuthentication.Shared/Middlewares/Login/DefaultLoginMiddlewareBuilder.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Builder; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login +{ + internal class DefaultLoginMiddlewareBuilder + { + private static Func _onLoginExecutingCallback = null; + private static Func _onLoginExecutedCallback = null; + private static BaseLoginEndpointOptions _loginEndpointOptions = new BaseLoginEndpointOptions(); + + private static bool _loginMiddlewareIsRegistered = false; + private static bool _executingCallbackIsRegistered = false; + private static bool _executedCallbackIsRegistered = false; + + private IApplicationBuilder _applicationBuilder; + + private static DefaultLoginMiddlewareBuilder _instance; + + private DefaultLoginMiddlewareBuilder() + { + } + + internal static DefaultLoginMiddlewareBuilder GetInstance() + { + if (_instance != null) + { + return _instance; + } + + _instance = new DefaultLoginMiddlewareBuilder(); + + return _instance; + } + + internal DefaultLoginMiddlewareBuilder SetAppBuilder(IApplicationBuilder applicationBuilder) + { + _applicationBuilder = applicationBuilder; + return this; + } + + internal DefaultLoginMiddlewareBuilder SetLoginEndpointOptions(BaseLoginEndpointOptions loginEndpointOptions = null) + { + if (loginEndpointOptions != null) + { + _loginEndpointOptions = loginEndpointOptions; + } + + return this; + } + + /// + /// Registering a callback function to perform actions when when the authentication starts. + /// + /// + /// + public IApplicationBuilder OnLoginExecuting(Func callback) + { + _onLoginExecutingCallback = callback; + _executingCallbackIsRegistered = true; + + if (!_loginMiddlewareIsRegistered) + { + return _applicationBuilder; + } + + return _applicationBuilder.UseMiddleware(_loginEndpointOptions, _onLoginExecutingCallback); + } + + /// + /// Registering a callback function to perform actions when the authentication ends. + /// + /// + /// + public IApplicationBuilder OnLoginExecuted(Func callback) + { + _onLoginExecutedCallback = callback; + _executedCallbackIsRegistered = true; + + if (!_loginMiddlewareIsRegistered) + { + return _applicationBuilder; + } + + return _applicationBuilder.UseMiddleware(_loginEndpointOptions, _onLoginExecutedCallback); + } + + /// + /// Adds middleware to handle incoming login requests. + /// + /// + /// + public IApplicationBuilder UseDefaultLoginMiddleware() + { + RegisterDefaultLoginMiddleware(); + return _applicationBuilder; + } + + private void RegisterDefaultLoginMiddleware() + { + var middlewareArguments = new List() { _loginEndpointOptions }; + + if (_executingCallbackIsRegistered) + { + middlewareArguments.Add(_onLoginExecutingCallback); + } + + if (_executedCallbackIsRegistered) + { + middlewareArguments.Add(_onLoginExecutedCallback); + } + + _applicationBuilder.UseMiddleware(middlewareArguments.ToArray()); + _loginMiddlewareIsRegistered = true; + } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Core/Middlewares/Login/LoginMiddleware.cs b/JwtAuthentication.Shared/Middlewares/Login/LoginMiddleware.cs similarity index 54% rename from JwtAuthentication.Core/Middlewares/Login/LoginMiddleware.cs rename to JwtAuthentication.Shared/Middlewares/Login/LoginMiddleware.cs index 9894f47..3521440 100644 --- a/JwtAuthentication.Core/Middlewares/Login/LoginMiddleware.cs +++ b/JwtAuthentication.Shared/Middlewares/Login/LoginMiddleware.cs @@ -1,27 +1,34 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login { internal class LoginMiddleware : RequestMiddlewareBase { - private readonly LoginEndpointOptions _loginEndpointOptions; + protected static BaseLoginEndpointOptions _loginEndpointOptions; + protected static Func _onLoginExecuting = null; + protected static Func _onLoginExecuted = null; - private readonly Func _onLoginExecuting; - private readonly Func _onLoginExecuted; - - public LoginMiddleware(RequestDelegate next, LoginEndpointOptions loginEndpointOptions, Func onLoginExecuting, Func onLoginExecuted) + public LoginMiddleware(RequestDelegate next, BaseLoginEndpointOptions loginEndpointOptions, Func onLoginExecuting = null, Func onLoginExecuted = null) : base(next) { _loginEndpointOptions = loginEndpointOptions; - _onLoginExecuting = onLoginExecuting; - _onLoginExecuted = onLoginExecuted; + + if (onLoginExecuting != null) + { + _onLoginExecuting = onLoginExecuting; + } + + if (onLoginExecuted != null) + { + _onLoginExecuted = onLoginExecuted; + } } public async Task InvokeAsync(HttpContext context, ILoginService loginService) @@ -38,16 +45,24 @@ protected override async Task ExecuteServiceMethod( try { - var contractLoginModel = new LoginModel + var contractLoginModel = new BasicLoginModel { Login = requestModel.Login, Password = requestModel.Password, ClientFingerPrint = requestModel.ClientFingerPrint, }; - await _onLoginExecuting(contractLoginModel); + if (_onLoginExecuting != null) + { + await _onLoginExecuting(contractLoginModel); + } + result = await service.LoginAsync(requestModel); - await _onLoginExecuted(contractLoginModel); + + if (_onLoginExecuted != null) + { + await _onLoginExecuted(contractLoginModel); + } } catch (Exception ex) { diff --git a/JwtAuthentication.Shared/Middlewares/Login/LoginMiddlewareWithExecutedCallback.cs b/JwtAuthentication.Shared/Middlewares/Login/LoginMiddlewareWithExecutedCallback.cs new file mode 100644 index 0000000..789b432 --- /dev/null +++ b/JwtAuthentication.Shared/Middlewares/Login/LoginMiddlewareWithExecutedCallback.cs @@ -0,0 +1,14 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login +{ + internal class LoginMiddlewareWithExecutedCallback : LoginMiddleware + { + public LoginMiddlewareWithExecutedCallback(RequestDelegate next, BaseLoginEndpointOptions loginEndpointOptions, Func onLoginExecuted) + : base(next, loginEndpointOptions, null, onLoginExecuted) { } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Middlewares/Login/LoginMiddlewareWithExecutingCallback.cs b/JwtAuthentication.Shared/Middlewares/Login/LoginMiddlewareWithExecutingCallback.cs new file mode 100644 index 0000000..631774d --- /dev/null +++ b/JwtAuthentication.Shared/Middlewares/Login/LoginMiddlewareWithExecutingCallback.cs @@ -0,0 +1,14 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login.Models; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login +{ + internal class LoginMiddlewareWithExecutingCallback : LoginMiddleware + { + public LoginMiddlewareWithExecutingCallback(RequestDelegate next, BaseLoginEndpointOptions loginEndpointOptions, Func onLoginExecuting) + : base(next, loginEndpointOptions, onLoginExecuting, null) { } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Middlewares/Login/Models/BasicLoginModel.cs b/JwtAuthentication.Shared/Middlewares/Login/Models/BasicLoginModel.cs new file mode 100644 index 0000000..52611b8 --- /dev/null +++ b/JwtAuthentication.Shared/Middlewares/Login/Models/BasicLoginModel.cs @@ -0,0 +1,11 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login.Models +{ + public class BasicLoginModel : IBasicLoginModel + { + public string Login { get; set; } + + public string Password { get; set; } + + public string ClientFingerPrint { get; set; } + } +} diff --git a/JwtAuthentication.Shared/Middlewares/Login/Models/IBasicLoginModel.cs b/JwtAuthentication.Shared/Middlewares/Login/Models/IBasicLoginModel.cs new file mode 100644 index 0000000..9641db0 --- /dev/null +++ b/JwtAuthentication.Shared/Middlewares/Login/Models/IBasicLoginModel.cs @@ -0,0 +1,11 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login.Models +{ + public interface IBasicLoginModel + { + public string Login { get; set; } + + public string Password { get; set; } + + public string ClientFingerPrint { get; set; } + } +} diff --git a/JwtAuthentication.Shared/TokenHandlers/DebugTokenHandler.cs b/JwtAuthentication.Shared/TokenHandlers/DebugTokenHandler.cs new file mode 100644 index 0000000..fded6e3 --- /dev/null +++ b/JwtAuthentication.Shared/TokenHandlers/DebugTokenHandler.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Text; +using System.Text.Encodings.Web; +using System.Text.Json; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenHandlers +{ + internal class DebugTokenHandler : AuthenticationHandler + { + public const string Schema = "DebugTokenAuthentication"; + + public const string HeaderName = "X-DEBUG-TOKEN"; + + public DebugTokenHandler( + IOptionsMonitor options, + ILoggerFactory logger, + UrlEncoder encoder, + ISystemClock clock) + : base(options, + logger, + encoder, + clock + ) + { + } + + /// + /// Searches the 'Authorization' header for a 'DebugToken' token. If the 'DebugToken' token is found, it is decoded from + /// base64. + /// + /// + protected override Task HandleAuthenticateAsync() + { + // skip authentication if endpoint has [AllowAnonymous] attribute + var endpoint = Context.GetEndpoint(); + + if (endpoint?.Metadata?.GetMetadata() != null) + { + return Task.FromResult(AuthenticateResult.NoResult()); + } + + try + { + string token = Request.Headers[HeaderName]; + + if (string.IsNullOrEmpty(token)) + { + return Task.FromResult(AuthenticateResult.NoResult()); + } + + var base64EncodedBytes = Convert.FromBase64String(token); + var decodedToken = Encoding.UTF8.GetString(base64EncodedBytes); + + var claims = JsonSerializer.Deserialize>(decodedToken) + .SelectMany(x => x.Value.ValueKind == JsonValueKind.Array + ? x.Value.EnumerateArray().Select(e => (x.Key, value: e.GetString())) + : new[] { (x.Key, value: x.Value.GetString()) } + ) + .Select(x => new Claim(x.Key, x.value)) + .ToList(); + + var claimsIdentity = new ClaimsIdentity(claims, Scheme.Name); + var principal = new ClaimsPrincipal(claimsIdentity); + var ticket = new AuthenticationTicket(principal, Scheme.Name); + return Task.FromResult(AuthenticateResult.Success(ticket)); + } + catch (Exception ex) + { + Logger.LogError(ex, "An error while login through DebugToken Scheme"); + return Task.FromResult(AuthenticateResult.Fail(ex)); + } + } + } +} \ No newline at end of file From ff25add9deb347aa3864c47e63214e08827bb9f1 Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Mon, 29 Aug 2022 14:06:29 +0500 Subject: [PATCH 24/34] chore: #60: enables cookie login middleware --- .../Startup.cs | 15 ++++--- .../ApplicationBuilderExtension.cs | 15 +++---- .../Options/CookieAuthOptions.cs | 7 +++- .../Options/LoginEndpointOptions.cs | 13 +++++- ...ion.cs => ApplicationBuilderExtensions.cs} | 40 +++++++++---------- .../CookieLogin}/LoginWithCookieMiddleware.cs | 12 +++--- .../TokenExtractionFromCookieMiddleware.cs | 8 ++-- .../Login/DefaultLoginMiddlewareBuilder.cs | 25 ++++-------- .../Middlewares/Login/LoginMiddleware.cs | 6 +-- .../LoginMiddlewareWithExecutedCallback.cs | 5 +-- .../LoginMiddlewareWithExecutingCallback.cs | 5 +-- .../Options/BaseCookieAuthOptions.cs | 4 +- .../Options/BaseLoginEndpointOptions.cs | 4 +- .../Options/Contracts/ICookieAuthOptions.cs | 7 ++++ .../Contracts/ILoginEndpointOptions.cs | 7 ++++ 15 files changed, 94 insertions(+), 79 deletions(-) rename JwtAuthentication.Shared/{ApplicationBuilderExtension.cs => ApplicationBuilderExtensions.cs} (77%) rename {JwtAuthentication.Core/Middlewares => JwtAuthentication.Shared/Middlewares/CookieLogin}/LoginWithCookieMiddleware.cs (83%) rename {JwtAuthentication.Core/Middlewares => JwtAuthentication.Shared/Middlewares/CookieLogin}/TokenExtractionFromCookieMiddleware.cs (72%) create mode 100644 JwtAuthentication.Shared/Options/Contracts/ICookieAuthOptions.cs create mode 100644 JwtAuthentication.Shared/Options/Contracts/ILoginEndpointOptions.cs diff --git a/Examples/Example.NetCore3.1.BaseAuthentication/Startup.cs b/Examples/Example.NetCore3.1.BaseAuthentication/Startup.cs index 5d200b9..a6404f4 100644 --- a/Examples/Example.NetCore3.1.BaseAuthentication/Startup.cs +++ b/Examples/Example.NetCore3.1.BaseAuthentication/Startup.cs @@ -37,11 +37,11 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) app.UseRouting(); - app - .OnLoginExecuting(OnLoginExecuting) - .OnLoginExecuted(OnLoginExecuted) - .UseDefaultLoginMiddleware() - .UseJwtAuthentication(); + //app + // .OnLoginExecuting(OnLoginExecuting) + // .OnLoginExecuted(OnLoginExecuted) + // .UseDefaultLoginMiddleware() + // .UseJwtAuthentication(); //app // .UseDefaultLoginMiddleware() @@ -74,6 +74,11 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) // .UseDefaultLoginMiddleware() // .UseJwtAuthentication(); + app.UseCookieLoginMiddleware(new CookieAuthOptions + { + Key = "ExampleCookieName", + }); + app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } diff --git a/JwtAuthentication.Core/ApplicationBuilderExtension.cs b/JwtAuthentication.Core/ApplicationBuilderExtension.cs index 4bdd5ff..a0213d1 100644 --- a/JwtAuthentication.Core/ApplicationBuilderExtension.cs +++ b/JwtAuthentication.Core/ApplicationBuilderExtension.cs @@ -1,7 +1,6 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; @@ -31,8 +30,8 @@ public static IApplicationBuilder UseJwtAuthentication(this IApplicationBuilder /// /// public static IApplicationBuilder UseDefaultLoginMiddleware(this IApplicationBuilder applicationBuilder, LoginEndpointOptions loginEndpointOptions = null) - { - return Shared.ApplicationBuilderExtension.UseDefaultLoginMiddleware(applicationBuilder, loginEndpointOptions); + { + return Shared.ApplicationBuilderExtensions.UseDefaultLoginMiddleware(applicationBuilder, loginEndpointOptions ?? new LoginEndpointOptions()); } /// @@ -41,11 +40,9 @@ public static IApplicationBuilder UseDefaultLoginMiddleware(this IApplicationBui /// /// /// - public static IApplicationBuilder UseCookieLoginMiddleware(this IApplicationBuilder applicationBuilder, CookieAuthOptions options, LoginEndpointOptions loginEndpointOptions = null) + public static IApplicationBuilder UseCookieLoginMiddleware(this IApplicationBuilder applicationBuilder, CookieAuthOptions cookieAuthOptions, LoginEndpointOptions loginEndpointOptions = null) { - return applicationBuilder - .UseMiddleware(options, loginEndpointOptions ?? new LoginEndpointOptions()) - .UseMiddleware(options); + return Shared.ApplicationBuilderExtensions.RegisterCookieLoginMiddleware(applicationBuilder, cookieAuthOptions, loginEndpointOptions ?? new LoginEndpointOptions()); } /// @@ -58,7 +55,7 @@ public static IApplicationBuilder OnLoginExecuting(this IApplicationBuilder appl { Func loginExecutingCallback = basicLoginModel => callback(LoginModel.MapFrom(basicLoginModel)); - return Shared.ApplicationBuilderExtension.OnLoginExecuting(applicationBuilder, loginExecutingCallback); + return Shared.ApplicationBuilderExtensions.OnLoginExecuting(applicationBuilder, loginExecutingCallback); } /// @@ -71,7 +68,7 @@ public static IApplicationBuilder OnLoginExecuted(this IApplicationBuilder appli { Func loginExecutedCallback = basicLoginModel => callback(LoginModel.MapFrom(basicLoginModel)); - return Shared.ApplicationBuilderExtension.OnLoginExecuted(applicationBuilder, loginExecutedCallback); + return Shared.ApplicationBuilderExtensions.OnLoginExecuted(applicationBuilder, loginExecutedCallback); } /// diff --git a/JwtAuthentication.Core/Options/CookieAuthOptions.cs b/JwtAuthentication.Core/Options/CookieAuthOptions.cs index cda049c..a57de4c 100644 --- a/JwtAuthentication.Core/Options/CookieAuthOptions.cs +++ b/JwtAuthentication.Core/Options/CookieAuthOptions.cs @@ -1,6 +1,9 @@ -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Options { - public class CookieAuthOptions : BaseCookieAuthOptions { } + public class CookieAuthOptions : ICookieAuthOptions + { + public string Key { get; set; } + } } \ No newline at end of file diff --git a/JwtAuthentication.Core/Options/LoginEndpointOptions.cs b/JwtAuthentication.Core/Options/LoginEndpointOptions.cs index 7462054..31fd3f8 100644 --- a/JwtAuthentication.Core/Options/LoginEndpointOptions.cs +++ b/JwtAuthentication.Core/Options/LoginEndpointOptions.cs @@ -1,6 +1,15 @@ -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Options { - public class LoginEndpointOptions : BaseLoginEndpointOptions { } + public class LoginEndpointOptions : ILoginEndpointOptions + { + private string _loginEndpointRoute; + + public string LoginEndpointRoute + { + get => _loginEndpointRoute ?? "/auth/login"; + set => _loginEndpointRoute = value; + } + } } \ No newline at end of file diff --git a/JwtAuthentication.Shared/ApplicationBuilderExtension.cs b/JwtAuthentication.Shared/ApplicationBuilderExtensions.cs similarity index 77% rename from JwtAuthentication.Shared/ApplicationBuilderExtension.cs rename to JwtAuthentication.Shared/ApplicationBuilderExtensions.cs index d6a5e13..b2a3929 100644 --- a/JwtAuthentication.Shared/ApplicationBuilderExtension.cs +++ b/JwtAuthentication.Shared/ApplicationBuilderExtensions.cs @@ -1,13 +1,14 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.CookieLogin; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared { - public static class ApplicationBuilderExtension + public static class ApplicationBuilderExtensions { /// /// Adds Authentication and Authorization to the app. @@ -27,32 +28,27 @@ public static IApplicationBuilder UseJwtAuthentication(this IApplicationBuilder /// /// /// - public static IApplicationBuilder UseDefaultLoginMiddleware(this IApplicationBuilder applicationBuilder, BaseLoginEndpointOptions loginEndpointOptions = null) + public static IApplicationBuilder UseDefaultLoginMiddleware(this IApplicationBuilder applicationBuilder, ILoginEndpointOptions loginEndpointOptions) { return DefaultLoginMiddlewareBuilder .GetInstance() .SetAppBuilder(applicationBuilder) - .SetLoginEndpointOptions(loginEndpointOptions) - .UseDefaultLoginMiddleware(); - - //Func defaultOnLoginCallback = s => Task.CompletedTask; - - //return applicationBuilder - // .UseMiddleware(loginEndpointOptions ?? new BaseLoginEndpointOptions(), defaultOnLoginCallback, defaultOnLoginCallback); + .UseDefaultLoginMiddleware(loginEndpointOptions); } - ///// - ///// Adds middleware to handle incoming login requests using cookies to store auth token. - ///// - ///// - ///// - ///// - //public static IApplicationBuilder UseCookieLoginMiddleware(this IApplicationBuilder applicationBuilder, CookieAuthOptions options, LoginEndpointOptions loginEndpointOptions = null) - //{ - // return applicationBuilder - // .UseMiddleware(options, loginEndpointOptions ?? new LoginEndpointOptions()) - // .UseMiddleware(options); - //} + /// + /// Adds middleware to handle incoming login requests using cookies to store auth token. + /// + /// + /// + /// + /// + public static IApplicationBuilder RegisterCookieLoginMiddleware(this IApplicationBuilder applicationBuilder, ICookieAuthOptions cookieAuthOptions, ILoginEndpointOptions loginEndpointOptions) + { + return applicationBuilder + .UseMiddleware(cookieAuthOptions, loginEndpointOptions) + .UseMiddleware(cookieAuthOptions); + } /// /// Registering a callback function to perform actions when when the authentication starts. diff --git a/JwtAuthentication.Core/Middlewares/LoginWithCookieMiddleware.cs b/JwtAuthentication.Shared/Middlewares/CookieLogin/LoginWithCookieMiddleware.cs similarity index 83% rename from JwtAuthentication.Core/Middlewares/LoginWithCookieMiddleware.cs rename to JwtAuthentication.Shared/Middlewares/CookieLogin/LoginWithCookieMiddleware.cs index ee26fef..19d5e55 100644 --- a/JwtAuthentication.Core/Middlewares/LoginWithCookieMiddleware.cs +++ b/JwtAuthentication.Shared/Middlewares/CookieLogin/LoginWithCookieMiddleware.cs @@ -1,22 +1,22 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.CookieLogin { internal class LoginWithCookieMiddleware : RequestMiddlewareBase { - private readonly CookieAuthOptions _cookieOptions; - private readonly LoginEndpointOptions _loginEndpointOptions; + private readonly ICookieAuthOptions _cookieOptions; + private readonly ILoginEndpointOptions _loginEndpointOptions; public LoginWithCookieMiddleware( RequestDelegate next, - CookieAuthOptions cookieOptions, - LoginEndpointOptions loginEndpointOptions) + ICookieAuthOptions cookieOptions, + ILoginEndpointOptions loginEndpointOptions) : base(next) { _cookieOptions = cookieOptions; diff --git a/JwtAuthentication.Core/Middlewares/TokenExtractionFromCookieMiddleware.cs b/JwtAuthentication.Shared/Middlewares/CookieLogin/TokenExtractionFromCookieMiddleware.cs similarity index 72% rename from JwtAuthentication.Core/Middlewares/TokenExtractionFromCookieMiddleware.cs rename to JwtAuthentication.Shared/Middlewares/CookieLogin/TokenExtractionFromCookieMiddleware.cs index e5f1cbe..33de5c5 100644 --- a/JwtAuthentication.Core/Middlewares/TokenExtractionFromCookieMiddleware.cs +++ b/JwtAuthentication.Shared/Middlewares/CookieLogin/TokenExtractionFromCookieMiddleware.cs @@ -1,15 +1,15 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.CookieLogin { public class TokenExtractionFromCookieMiddleware { private readonly RequestDelegate _next; - private readonly CookieAuthOptions _options; + private readonly ICookieAuthOptions _options; - public TokenExtractionFromCookieMiddleware(RequestDelegate next, CookieAuthOptions options) + public TokenExtractionFromCookieMiddleware(RequestDelegate next, ICookieAuthOptions options) { _next = next; _options = options; diff --git a/JwtAuthentication.Shared/Middlewares/Login/DefaultLoginMiddlewareBuilder.cs b/JwtAuthentication.Shared/Middlewares/Login/DefaultLoginMiddlewareBuilder.cs index eeab7e6..ca859f5 100644 --- a/JwtAuthentication.Shared/Middlewares/Login/DefaultLoginMiddlewareBuilder.cs +++ b/JwtAuthentication.Shared/Middlewares/Login/DefaultLoginMiddlewareBuilder.cs @@ -3,7 +3,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login { @@ -11,7 +11,6 @@ internal class DefaultLoginMiddlewareBuilder { private static Func _onLoginExecutingCallback = null; private static Func _onLoginExecutedCallback = null; - private static BaseLoginEndpointOptions _loginEndpointOptions = new BaseLoginEndpointOptions(); private static bool _loginMiddlewareIsRegistered = false; private static bool _executingCallbackIsRegistered = false; @@ -43,16 +42,6 @@ internal DefaultLoginMiddlewareBuilder SetAppBuilder(IApplicationBuilder applica return this; } - internal DefaultLoginMiddlewareBuilder SetLoginEndpointOptions(BaseLoginEndpointOptions loginEndpointOptions = null) - { - if (loginEndpointOptions != null) - { - _loginEndpointOptions = loginEndpointOptions; - } - - return this; - } - /// /// Registering a callback function to perform actions when when the authentication starts. /// @@ -68,7 +57,7 @@ public IApplicationBuilder OnLoginExecuting(Func callback return _applicationBuilder; } - return _applicationBuilder.UseMiddleware(_loginEndpointOptions, _onLoginExecutingCallback); + return _applicationBuilder.UseMiddleware(_onLoginExecutingCallback); } /// @@ -86,7 +75,7 @@ public IApplicationBuilder OnLoginExecuted(Func callback) return _applicationBuilder; } - return _applicationBuilder.UseMiddleware(_loginEndpointOptions, _onLoginExecutedCallback); + return _applicationBuilder.UseMiddleware(_onLoginExecutedCallback); } /// @@ -94,15 +83,15 @@ public IApplicationBuilder OnLoginExecuted(Func callback) /// /// /// - public IApplicationBuilder UseDefaultLoginMiddleware() + public IApplicationBuilder UseDefaultLoginMiddleware(ILoginEndpointOptions loginEndpointOptions) { - RegisterDefaultLoginMiddleware(); + RegisterDefaultLoginMiddleware(loginEndpointOptions); return _applicationBuilder; } - private void RegisterDefaultLoginMiddleware() + private void RegisterDefaultLoginMiddleware(ILoginEndpointOptions loginEndpointOptions) { - var middlewareArguments = new List() { _loginEndpointOptions }; + var middlewareArguments = new List() { loginEndpointOptions }; if (_executingCallbackIsRegistered) { diff --git a/JwtAuthentication.Shared/Middlewares/Login/LoginMiddleware.cs b/JwtAuthentication.Shared/Middlewares/Login/LoginMiddleware.cs index 3521440..0bf4a4b 100644 --- a/JwtAuthentication.Shared/Middlewares/Login/LoginMiddleware.cs +++ b/JwtAuthentication.Shared/Middlewares/Login/LoginMiddleware.cs @@ -4,18 +4,18 @@ using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login { internal class LoginMiddleware : RequestMiddlewareBase { - protected static BaseLoginEndpointOptions _loginEndpointOptions; + protected static ILoginEndpointOptions _loginEndpointOptions; protected static Func _onLoginExecuting = null; protected static Func _onLoginExecuted = null; - public LoginMiddleware(RequestDelegate next, BaseLoginEndpointOptions loginEndpointOptions, Func onLoginExecuting = null, Func onLoginExecuted = null) + public LoginMiddleware(RequestDelegate next, ILoginEndpointOptions loginEndpointOptions, Func onLoginExecuting = null, Func onLoginExecuted = null) : base(next) { _loginEndpointOptions = loginEndpointOptions; diff --git a/JwtAuthentication.Shared/Middlewares/Login/LoginMiddlewareWithExecutedCallback.cs b/JwtAuthentication.Shared/Middlewares/Login/LoginMiddlewareWithExecutedCallback.cs index 789b432..e30b60b 100644 --- a/JwtAuthentication.Shared/Middlewares/Login/LoginMiddlewareWithExecutedCallback.cs +++ b/JwtAuthentication.Shared/Middlewares/Login/LoginMiddlewareWithExecutedCallback.cs @@ -2,13 +2,12 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login { internal class LoginMiddlewareWithExecutedCallback : LoginMiddleware { - public LoginMiddlewareWithExecutedCallback(RequestDelegate next, BaseLoginEndpointOptions loginEndpointOptions, Func onLoginExecuted) - : base(next, loginEndpointOptions, null, onLoginExecuted) { } + public LoginMiddlewareWithExecutedCallback(RequestDelegate next, Func onLoginExecuted) + : base(next, null, null, onLoginExecuted) { } } } \ No newline at end of file diff --git a/JwtAuthentication.Shared/Middlewares/Login/LoginMiddlewareWithExecutingCallback.cs b/JwtAuthentication.Shared/Middlewares/Login/LoginMiddlewareWithExecutingCallback.cs index 631774d..e6940a8 100644 --- a/JwtAuthentication.Shared/Middlewares/Login/LoginMiddlewareWithExecutingCallback.cs +++ b/JwtAuthentication.Shared/Middlewares/Login/LoginMiddlewareWithExecutingCallback.cs @@ -2,13 +2,12 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login { internal class LoginMiddlewareWithExecutingCallback : LoginMiddleware { - public LoginMiddlewareWithExecutingCallback(RequestDelegate next, BaseLoginEndpointOptions loginEndpointOptions, Func onLoginExecuting) - : base(next, loginEndpointOptions, onLoginExecuting, null) { } + public LoginMiddlewareWithExecutingCallback(RequestDelegate next, Func onLoginExecuting) + : base(next, null, onLoginExecuting, null) { } } } \ No newline at end of file diff --git a/JwtAuthentication.Shared/Options/BaseCookieAuthOptions.cs b/JwtAuthentication.Shared/Options/BaseCookieAuthOptions.cs index bc9a99e..5802a3f 100644 --- a/JwtAuthentication.Shared/Options/BaseCookieAuthOptions.cs +++ b/JwtAuthentication.Shared/Options/BaseCookieAuthOptions.cs @@ -1,6 +1,8 @@ +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options { - public class BaseCookieAuthOptions + public class BaseCookieAuthOptions : ICookieAuthOptions { public string Key { get; set; } } diff --git a/JwtAuthentication.Shared/Options/BaseLoginEndpointOptions.cs b/JwtAuthentication.Shared/Options/BaseLoginEndpointOptions.cs index 56d5a21..f806c26 100644 --- a/JwtAuthentication.Shared/Options/BaseLoginEndpointOptions.cs +++ b/JwtAuthentication.Shared/Options/BaseLoginEndpointOptions.cs @@ -1,6 +1,8 @@ +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; + namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options { - public class BaseLoginEndpointOptions + public class BaseLoginEndpointOptions : ILoginEndpointOptions { private string _loginEndpointRoute; diff --git a/JwtAuthentication.Shared/Options/Contracts/ICookieAuthOptions.cs b/JwtAuthentication.Shared/Options/Contracts/ICookieAuthOptions.cs new file mode 100644 index 0000000..e8ae461 --- /dev/null +++ b/JwtAuthentication.Shared/Options/Contracts/ICookieAuthOptions.cs @@ -0,0 +1,7 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts +{ + public interface ICookieAuthOptions + { + public string Key { get; set; } + } +} diff --git a/JwtAuthentication.Shared/Options/Contracts/ILoginEndpointOptions.cs b/JwtAuthentication.Shared/Options/Contracts/ILoginEndpointOptions.cs new file mode 100644 index 0000000..e447cb0 --- /dev/null +++ b/JwtAuthentication.Shared/Options/Contracts/ILoginEndpointOptions.cs @@ -0,0 +1,7 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts +{ + public interface ILoginEndpointOptions + { + public string LoginEndpointRoute { get; set; } + } +} From 2873c9e52a7da2bcdfb4583bb7d32ca35f4ec21e Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Mon, 29 Aug 2022 14:36:58 +0500 Subject: [PATCH 25/34] chore: #60: removes refresh section from shared project --- .../ApplicationBuilderExtensions.cs | 42 ------------------- 1 file changed, 42 deletions(-) diff --git a/JwtAuthentication.Shared/ApplicationBuilderExtensions.cs b/JwtAuthentication.Shared/ApplicationBuilderExtensions.cs index b2a3929..8a39f2d 100644 --- a/JwtAuthentication.Shared/ApplicationBuilderExtensions.cs +++ b/JwtAuthentication.Shared/ApplicationBuilderExtensions.cs @@ -77,47 +77,5 @@ public static IApplicationBuilder OnLoginExecuted(this IApplicationBuilder appli .SetAppBuilder(applicationBuilder) .OnLoginExecuted(callback); } - - ///// - ///// Adds middleware to handle incoming login and token refresh requests. - ///// - ///// - ///// - ///// - //public static IApplicationBuilder UseRefreshTokenMiddleware(this IApplicationBuilder applicationBuilder, RefreshEndpointOptions endpointOptions = null) - //{ - // Func defaultOnRefreshCallback = s => Task.CompletedTask; - - // return applicationBuilder - // .UseMiddleware(endpointOptions ?? new RefreshEndpointOptions(), defaultOnRefreshCallback, defaultOnRefreshCallback); - //} - - ///// - ///// Registering a callback function to perform actions when when the refresh starts. - ///// - ///// - ///// - ///// - //public static IRefreshMiddlewareBuilder OnRefreshExecuting(this IApplicationBuilder applicationBuilder, Func callback) - //{ - // return RefreshMiddlewareBuilder - // .GetInstance() - // .SetAppBuilder(applicationBuilder) - // .OnRefreshExecuting(callback); - //} - - ///// - ///// Registering a callback function to perform actions when the refresh ends. - ///// - ///// - ///// - ///// - //public static IRefreshMiddlewareBuilder OnRefreshExecuted(this IApplicationBuilder applicationBuilder, Func callback) - //{ - // return RefreshMiddlewareBuilder - // .GetInstance() - // .SetAppBuilder(applicationBuilder) - // .OnRefreshExecuted(callback); - //} } } \ No newline at end of file From e12c417731be634b3a92f9e762c174613d646f8d Mon Sep 17 00:00:00 2001 From: iamvladislove Date: Tue, 30 Aug 2022 09:16:28 +0500 Subject: [PATCH 26/34] chore: #60: removes unused code --- .../Middlewares/Refresh/RefreshMiddleware.cs | 1 + .../Middlewares/RequestMiddlewareBase.cs | 118 ------------------ .../Options/RefreshTokenOptions.cs | 8 +- 3 files changed, 5 insertions(+), 122 deletions(-) delete mode 100644 JwtAuthentication.Core/Middlewares/RequestMiddlewareBase.cs diff --git a/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs b/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs index 86e21ff..fdec721 100644 --- a/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs +++ b/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs @@ -6,6 +6,7 @@ using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Requests; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh diff --git a/JwtAuthentication.Core/Middlewares/RequestMiddlewareBase.cs b/JwtAuthentication.Core/Middlewares/RequestMiddlewareBase.cs deleted file mode 100644 index 66df5d0..0000000 --- a/JwtAuthentication.Core/Middlewares/RequestMiddlewareBase.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; -#if NETCOREAPP3_0 || NETCOREAPP3_1 -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using Newtonsoft.Json.Serialization; - -#else -using System.Text.Json; -using System.Text.Json.Serialization; -#endif - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares -{ - internal abstract class RequestMiddlewareBase - { - private readonly RequestDelegate _next; -#if NETCOREAPP3_0 || NETCOREAPP3_1 - private readonly JsonSerializerSettings _jsonSerializerSettings; -#else - private readonly JsonSerializerOptions _jsonSerializerSettings; -#endif - protected RequestMiddlewareBase(RequestDelegate next) - { - _next = next; - -#if NETCOREAPP3_0 || NETCOREAPP3_1 - _jsonSerializerSettings = new JsonSerializerSettings - { - Formatting = Formatting.Indented, - NullValueHandling = NullValueHandling.Ignore, - Converters = - { - new IsoDateTimeConverter(), - new StringEnumConverter(), - }, - ContractResolver = new CamelCasePropertyNamesContractResolver(), - }; -#else - _jsonSerializerSettings = new JsonSerializerOptions - { - IgnoreNullValues = true, - AllowTrailingCommas = true, - WriteIndented = true, - PropertyNameCaseInsensitive = true, - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - Converters = - { - new JsonStringEnumConverter(), - }, - }; -#endif - } - - protected async Task InvokeAsyncBase(HttpContext context, TService service, string endpointRoute) - { - try - { - if (context.Request.Method == HttpMethods.Post) - { - var endpoint = context.Request.Path.Value; - - if (endpoint.EndsWith(endpointRoute)) - { - var requestModel = await DeserializeModel(context.Request); - - var result = await ExecuteServiceMethod(requestModel, service, context); - - if (result != null) - { - await Response(context, result); - return; - } - } - } - } - catch (Exception ex) - { - var errorModelExample = new - { - ErrorMessage = ex.Message, - }; - - await Response(context, errorModelExample); - return; - } - - await _next(context); - } - - private async Task Response(HttpContext context, T result) - { - context.Response.ContentType = "application/json; charset=UTF-8"; -#if NETCOREAPP3_0 || NETCOREAPP3_1 - await context.Response.WriteAsync(JsonConvert.SerializeObject(result, _jsonSerializerSettings)); -#else - await context.Response.WriteAsync(JsonSerializer.Serialize(result, _jsonSerializerSettings)); -#endif - await context.Response.Body.FlushAsync(); - } - - private async Task DeserializeModel(HttpRequest request) - { - using (var reader = new StreamReader(request.Body)) - { -#if NETCOREAPP3_0 || NETCOREAPP3_1 - return JsonConvert.DeserializeObject(await reader.ReadToEndAsync(), _jsonSerializerSettings); -#else - return JsonSerializer.Deserialize(await reader.ReadToEndAsync(), _jsonSerializerSettings); -#endif - } - } - - protected abstract Task ExecuteServiceMethod(TRequestModel requestModel, TService service, HttpContext context); - } -} \ No newline at end of file diff --git a/JwtAuthentication.Core/Options/RefreshTokenOptions.cs b/JwtAuthentication.Core/Options/RefreshTokenOptions.cs index af00f8c..b661866 100644 --- a/JwtAuthentication.Core/Options/RefreshTokenOptions.cs +++ b/JwtAuthentication.Core/Options/RefreshTokenOptions.cs @@ -1,6 +1,6 @@ using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Options -{ - public class RefreshTokenOptions : BaseRefreshTokenOptions { } -} +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Options +{ + public class RefreshTokenOptions : BaseRefreshTokenOptions { } +} From e1b05aa4f78566ba8a1ba0f68513a1db83667898 Mon Sep 17 00:00:00 2001 From: iamvladislove Date: Tue, 30 Aug 2022 13:35:30 +0500 Subject: [PATCH 27/34] chore: #60: adds a .netcore3.1 project example with permissions --- AspNetCore.JwtAuthentication.sln | 7 +++ .../Controllers/ExampleController.cs | 34 ++++++++++++++ .../CustomUserClaimsProvider.cs | 26 +++++++++++ ...re3.1.PermissionBasedAuthentication.csproj | 13 ++++++ .../Program.cs | 19 ++++++++ .../Properties/launchSettings.json | 30 +++++++++++++ .../Startup.cs | 45 +++++++++++++++++++ .../appsettings.json | 6 +++ .../AuthenticationExtensions.cs | 22 +++------ .../Contracts/UserClaimsProvider.cs | 12 +++++ .../Filters/RequiresPermission.cs | 31 ++++++++++++- .../Filters/RequiresPermission.cs | 31 ++++++++++++- .../AuthenticationExtensions.cs | 41 ++++++++++++++++- .../Extensions/ClaimsPrincipalExtensions.cs | 2 +- .../Filters/BaseRequiresPermission.cs | 33 -------------- 15 files changed, 296 insertions(+), 56 deletions(-) create mode 100644 Examples/Example.NetCore3.1.PermissionBasedAuthentication/Controllers/ExampleController.cs create mode 100644 Examples/Example.NetCore3.1.PermissionBasedAuthentication/CustomUserClaimsProvider.cs create mode 100644 Examples/Example.NetCore3.1.PermissionBasedAuthentication/Example.NetCore3.1.PermissionBasedAuthentication.csproj create mode 100644 Examples/Example.NetCore3.1.PermissionBasedAuthentication/Program.cs create mode 100644 Examples/Example.NetCore3.1.PermissionBasedAuthentication/Properties/launchSettings.json create mode 100644 Examples/Example.NetCore3.1.PermissionBasedAuthentication/Startup.cs create mode 100644 Examples/Example.NetCore3.1.PermissionBasedAuthentication/appsettings.json create mode 100644 JwtAuthentication.Core/Contracts/UserClaimsProvider.cs delete mode 100644 JwtAuthentication.Shared/Filters/BaseRequiresPermission.cs diff --git a/AspNetCore.JwtAuthentication.sln b/AspNetCore.JwtAuthentication.sln index e79aa7d..2d88c48 100644 --- a/AspNetCore.JwtAuthentication.sln +++ b/AspNetCore.JwtAuthentication.sln @@ -62,6 +62,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore3.1.Authenti EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JwtAuthentication.Shared", "JwtAuthentication.Shared\JwtAuthentication.Shared.csproj", "{E1952561-A7CD-45C3-B9D0-AC9B92A194CC}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.NetCore3.1.PermissionBasedAuthentication", "Examples\Example.NetCore3.1.PermissionBasedAuthentication\Example.NetCore3.1.PermissionBasedAuthentication.csproj", "{7397D805-384D-4E60-A7BC-E650664231D0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -160,6 +162,10 @@ Global {E1952561-A7CD-45C3-B9D0-AC9B92A194CC}.Debug|Any CPU.Build.0 = Debug|Any CPU {E1952561-A7CD-45C3-B9D0-AC9B92A194CC}.Release|Any CPU.ActiveCfg = Release|Any CPU {E1952561-A7CD-45C3-B9D0-AC9B92A194CC}.Release|Any CPU.Build.0 = Release|Any CPU + {7397D805-384D-4E60-A7BC-E650664231D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7397D805-384D-4E60-A7BC-E650664231D0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7397D805-384D-4E60-A7BC-E650664231D0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7397D805-384D-4E60-A7BC-E650664231D0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -188,6 +194,7 @@ Global {ABDD94F3-DF9E-47B2-813F-935C54C8DEA7} = {4FF83CB3-A634-4D07-BEE0-B5391B86F071} {F0E28B79-7957-444F-B437-D2EEC072A6DE} = {7A925031-2656-4CEB-821A-D76739E0E5A2} {63E8464D-8489-4423-ADCD-1107DC5D9336} = {614DB4C6-A4BE-4BBF-B385-C34985CA1FC3} + {7397D805-384D-4E60-A7BC-E650664231D0} = {614DB4C6-A4BE-4BBF-B385-C34985CA1FC3} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C2026BF9-DACC-4EA4-AF04-B8A590EA38BF} diff --git a/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Controllers/ExampleController.cs b/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Controllers/ExampleController.cs new file mode 100644 index 0000000..23b326d --- /dev/null +++ b/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Controllers/ExampleController.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Filters; + +namespace Example.NetCore3._1.PermissionBasedAuthentication.Controllers +{ + [ApiController] + [Route("[controller]")] + public class ExampleController : ControllerBase + { + private static readonly string[] Summaries = + { + "Freezing", + "Bracing", + "Chilly", + "Cool", + "Mild", + "Warm", + "Balmy", + "Hot", + "Sweltering", + "Scorching", + }; + + [Authorize] + [RequiresPermission(CustomUserClaimsProvider.FirstExampleClaimName)] + [HttpGet] + public IEnumerable Get() + { + return Summaries; + } + } +} \ No newline at end of file diff --git a/Examples/Example.NetCore3.1.PermissionBasedAuthentication/CustomUserClaimsProvider.cs b/Examples/Example.NetCore3.1.PermissionBasedAuthentication/CustomUserClaimsProvider.cs new file mode 100644 index 0000000..1fa8743 --- /dev/null +++ b/Examples/Example.NetCore3.1.PermissionBasedAuthentication/CustomUserClaimsProvider.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contracts; + +namespace Example.NetCore3._1.PermissionBasedAuthentication +{ + public class CustomUserClaimsProvider : UserClaimsProvider + { + public const string ExampleClaimType = "ExamplePermission"; + + public const string FirstExampleClaimName = "CanUseExampleFirst"; + + public const string SecondExampleClaimName = "CanUseExampleSecond"; + + public override Task> GetUserClaimsAsync(string login) + { + return Task.FromResult(new List + { + new Claim(ExampleClaimType, FirstExampleClaimName), + new Claim(ExampleClaimType, SecondExampleClaimName), + } + ); + } + } +} \ No newline at end of file diff --git a/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Example.NetCore3.1.PermissionBasedAuthentication.csproj b/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Example.NetCore3.1.PermissionBasedAuthentication.csproj new file mode 100644 index 0000000..b995f4c --- /dev/null +++ b/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Example.NetCore3.1.PermissionBasedAuthentication.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + Example.NetCore3._1.PermissionBasedAuthentication + + + + + + + + diff --git a/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Program.cs b/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Program.cs new file mode 100644 index 0000000..f8e4c4e --- /dev/null +++ b/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Program.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace Example.NetCore3._1.PermissionBasedAuthentication +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) + { + return Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); + } + } +} diff --git a/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Properties/launchSettings.json b/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Properties/launchSettings.json new file mode 100644 index 0000000..5ac2db1 --- /dev/null +++ b/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Properties/launchSettings.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:23693", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "example", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Example.NetCore3._1.PermissionBasedAuthentication": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "example", + "applicationUrl": "http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Startup.cs b/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Startup.cs new file mode 100644 index 0000000..1b62293 --- /dev/null +++ b/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Startup.cs @@ -0,0 +1,45 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using TourmalineCore.AspNetCore.JwtAuthentication.Core; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; + +namespace Example.NetCore3._1.PermissionBasedAuthentication +{ + public class Startup + { + private readonly IConfiguration _configuration; + + public Startup(IConfiguration configuration) + { + _configuration = configuration; + } + + public void ConfigureServices(IServiceCollection services) + { + services + .AddJwtAuthentication(_configuration.GetSection(nameof(AuthenticationOptions)).Get()) + .WithUserClaimsProvider(CustomUserClaimsProvider.ExampleClaimType); + + services.AddControllers(); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + + app + .UseDefaultLoginMiddleware() + .UseJwtAuthentication(); + + app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); + } + } +} diff --git a/Examples/Example.NetCore3.1.PermissionBasedAuthentication/appsettings.json b/Examples/Example.NetCore3.1.PermissionBasedAuthentication/appsettings.json new file mode 100644 index 0000000..d09d8c4 --- /dev/null +++ b/Examples/Example.NetCore3.1.PermissionBasedAuthentication/appsettings.json @@ -0,0 +1,6 @@ +{ + "AuthenticationOptions": { + "PublicSigningKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQAB", + "PrivateSigningKey": "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU" + } +} \ No newline at end of file diff --git a/JwtAuthentication.Core/AuthenticationExtensions.cs b/JwtAuthentication.Core/AuthenticationExtensions.cs index 174e4ad..8f45aa5 100644 --- a/JwtAuthentication.Core/AuthenticationExtensions.cs +++ b/JwtAuthentication.Core/AuthenticationExtensions.cs @@ -17,6 +17,7 @@ using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core { @@ -32,9 +33,7 @@ public static IServiceCollection AddJwtValidation( this IServiceCollection services, AuthenticationOptions authenticationOptions) { - services.AddJwtBearer(authenticationOptions); - - return services; + return Shared.AuthenticationExtensions.AddJwtValidation(services, authenticationOptions); } /// @@ -48,16 +47,6 @@ public static IServiceCollection AddJwtAuthentication( AuthenticationOptions authenticationOptions) { return Shared.AuthenticationExtensions.AddJwtAuthentication(services, authenticationOptions); - - //services.AddTransient(); - //services.AddTransient(); - //services.AddTransient(); - //services.AddTransient(); - //services.AddTransient(); - - //services.AddJwtBearer(authenticationOptions); - - //return services; } /// @@ -69,7 +58,7 @@ public static IServiceCollection AddJwtAuthentication( public static IServiceCollection AddUserCredentialValidator(this IServiceCollection services) where TUserCredentialsValidator : IUserCredentialsValidator { - return services.AddTransient(typeof(IUserCredentialsValidator), typeof(TUserCredentialsValidator)); + return Shared.AuthenticationExtensions.AddUserCredentialValidator(services); } /// @@ -82,11 +71,10 @@ public static IServiceCollection AddUserCredentialValidator( this IServiceCollection services, string permissionClaimTypeKey = "Permission") - where TUserClaimsProvider : IUserClaimsProvider + where TUserClaimsProvider : UserClaimsProvider { RequiresPermission.ClaimType = permissionClaimTypeKey; - - return services.AddTransient(typeof(IUserClaimsProvider), typeof(TUserClaimsProvider)); + return Shared.AuthenticationExtensions.WithUserClaimsProvider(services); } public static IServiceCollection AddLoginWithRefresh( diff --git a/JwtAuthentication.Core/Contracts/UserClaimsProvider.cs b/JwtAuthentication.Core/Contracts/UserClaimsProvider.cs new file mode 100644 index 0000000..8a4f25e --- /dev/null +++ b/JwtAuthentication.Core/Contracts/UserClaimsProvider.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contracts +{ + public abstract class UserClaimsProvider : IUserClaimsProvider + { + public abstract Task> GetUserClaimsAsync(string login); + } +} diff --git a/JwtAuthentication.Core/Filters/RequiresPermission.cs b/JwtAuthentication.Core/Filters/RequiresPermission.cs index 808cc7a..2c7f755 100644 --- a/JwtAuthentication.Core/Filters/RequiresPermission.cs +++ b/JwtAuthentication.Core/Filters/RequiresPermission.cs @@ -1,6 +1,33 @@ -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Filters; +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Extensions; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Filters { - public class RequiresPermission : BaseRequiresPermission { } + public class RequiresPermission : Attribute, IAuthorizationFilter + { + public static string ClaimType; + + private readonly List _permissions; + + public RequiresPermission(params string[] permissions) + { + _permissions = permissions.ToList(); + } + + public void OnAuthorization(AuthorizationFilterContext context) + { + var user = context.HttpContext.User; + + if (_permissions.Any(x => user.HasPermission(ClaimType, x))) + { + return; + } + + context.Result = new ForbidResult(); + } + } } \ No newline at end of file diff --git a/JwtAuthentication.Identity/Filters/RequiresPermission.cs b/JwtAuthentication.Identity/Filters/RequiresPermission.cs index 7523a88..7b08941 100644 --- a/JwtAuthentication.Identity/Filters/RequiresPermission.cs +++ b/JwtAuthentication.Identity/Filters/RequiresPermission.cs @@ -1,6 +1,33 @@ -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Filters; +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Extensions; namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Filters { - public class RequiresPermission : BaseRequiresPermission { } + public class RequiresPermission : Attribute, IAuthorizationFilter + { + public static string ClaimType; + + private readonly List _permissions; + + public RequiresPermission(params string[] permissions) + { + _permissions = permissions.ToList(); + } + + public void OnAuthorization(AuthorizationFilterContext context) + { + var user = context.HttpContext.User; + + if (_permissions.Any(x => user.HasPermission(ClaimType, x))) + { + return; + } + + context.Result = new ForbidResult(); + } + } } \ No newline at end of file diff --git a/JwtAuthentication.Shared/AuthenticationExtensions.cs b/JwtAuthentication.Shared/AuthenticationExtensions.cs index 6b8cd82..678a8fd 100644 --- a/JwtAuthentication.Shared/AuthenticationExtensions.cs +++ b/JwtAuthentication.Shared/AuthenticationExtensions.cs @@ -5,7 +5,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares.Login.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; @@ -20,6 +19,21 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared { public static class AuthenticationExtensions { + /// + /// Adds the ability to validate JWT + /// + /// + /// + /// + public static IServiceCollection AddJwtValidation( + IServiceCollection services, + BaseAuthenticationOptions authenticationOptions) + { + services.AddJwtBearer(authenticationOptions); + + return services; + } + /// /// Adds the ability to use the basic functionality of JWT /// @@ -41,6 +55,31 @@ public static IServiceCollection AddJwtAuthentication( return services; } + /// + /// Allows to implement custom logic for checking the username and password + /// + /// + /// + /// + public static IServiceCollection AddUserCredentialValidator(IServiceCollection services) + where TUserCredentialsValidator : IUserCredentialsValidator + { + return services.AddTransient(typeof(IUserCredentialsValidator), typeof(TUserCredentialsValidator)); + } + + /// + /// Adds the ability to implement functionality for retrieving user claims + /// + /// + /// + /// + /// + public static IServiceCollection WithUserClaimsProvider(IServiceCollection services) + where TUserClaimsProvider : IUserClaimsProvider + { + return services.AddTransient(typeof(IUserClaimsProvider), typeof(TUserClaimsProvider)); + } + public static void AddJwtBearer( this IServiceCollection services, BaseAuthenticationOptions authenticationOptions) diff --git a/JwtAuthentication.Shared/Extensions/ClaimsPrincipalExtensions.cs b/JwtAuthentication.Shared/Extensions/ClaimsPrincipalExtensions.cs index d2f4932..da41a92 100644 --- a/JwtAuthentication.Shared/Extensions/ClaimsPrincipalExtensions.cs +++ b/JwtAuthentication.Shared/Extensions/ClaimsPrincipalExtensions.cs @@ -4,7 +4,7 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Extensions { - internal static class ClaimsPrincipalExtensions + public static class ClaimsPrincipalExtensions { public static bool HasPermission(this ClaimsPrincipal claimsPrincipal, string permissionType, string permissionName) { diff --git a/JwtAuthentication.Shared/Filters/BaseRequiresPermission.cs b/JwtAuthentication.Shared/Filters/BaseRequiresPermission.cs deleted file mode 100644 index e6871b2..0000000 --- a/JwtAuthentication.Shared/Filters/BaseRequiresPermission.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Extensions; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Filters -{ - public class BaseRequiresPermission : Attribute, IAuthorizationFilter - { - public static string ClaimType; - - private readonly List _permissions; - - public BaseRequiresPermission(params string[] permissions) - { - _permissions = permissions.ToList(); - } - - public void OnAuthorization(AuthorizationFilterContext context) - { - var user = context.HttpContext.User; - - if (_permissions.Any(x => user.HasPermission(ClaimType, x))) - { - return; - } - - context.Result = new ForbidResult(); - } - } -} \ No newline at end of file From 44cb61a10dd3cbef9a45d0838369434fd813438e Mon Sep 17 00:00:00 2001 From: iamvladislove Date: Tue, 30 Aug 2022 14:23:07 +0500 Subject: [PATCH 28/34] chore: #60: removes unnecessary code --- .../ApplicationBuilderExtension.cs | 6 +- .../AuthenticationExtensions.cs | 59 +------------ .../TokenHandlers/DebugTokenHandler.cs | 83 ------------------- 3 files changed, 4 insertions(+), 144 deletions(-) delete mode 100644 JwtAuthentication.Core/TokenHandlers/DebugTokenHandler.cs diff --git a/JwtAuthentication.Core/ApplicationBuilderExtension.cs b/JwtAuthentication.Core/ApplicationBuilderExtension.cs index a0213d1..66b8082 100644 --- a/JwtAuthentication.Core/ApplicationBuilderExtension.cs +++ b/JwtAuthentication.Core/ApplicationBuilderExtension.cs @@ -18,9 +18,7 @@ public static class ApplicationBuilderExtension /// public static IApplicationBuilder UseJwtAuthentication(this IApplicationBuilder applicationBuilder) { - return applicationBuilder - .UseAuthentication() - .UseAuthorization(); + return Shared.ApplicationBuilderExtensions.UseJwtAuthentication(applicationBuilder); } /// @@ -86,7 +84,7 @@ public static IApplicationBuilder UseRefreshTokenMiddleware(this IApplicationBui } /// - /// Registering a callback function to perform actions when when the refresh starts. + /// Registering a callback function to perform actions when the refresh starts. /// /// /// diff --git a/JwtAuthentication.Core/AuthenticationExtensions.cs b/JwtAuthentication.Core/AuthenticationExtensions.cs index 8f45aa5..f96f7dc 100644 --- a/JwtAuthentication.Core/AuthenticationExtensions.cs +++ b/JwtAuthentication.Core/AuthenticationExtensions.cs @@ -1,16 +1,8 @@ -using System; -using System.IdentityModel.Tokens.Jwt; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; -using Microsoft.IdentityModel.Tokens; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Filters; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.TokenHandlers; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Signing; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; using AuthenticationOptions = TourmalineCore.AspNetCore.JwtAuthentication.Core.Options.AuthenticationOptions; @@ -56,7 +48,7 @@ public static IServiceCollection AddJwtAuthentication( /// /// public static IServiceCollection AddUserCredentialValidator(this IServiceCollection services) - where TUserCredentialsValidator : IUserCredentialsValidator + where TUserCredentialsValidator : UserCredentialsValidator { return Shared.AuthenticationExtensions.AddUserCredentialValidator(services); } @@ -89,53 +81,6 @@ public static IServiceCollection AddLoginWithRefresh( services.AddTransient(); return services; - } - - internal static void AddJwtBearer( - this IServiceCollection services, - AuthenticationOptions authenticationOptions) - { - services.AddSingleton(authenticationOptions); - - JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); - - Func schemeSelector = context => null; - - var authBuilder = services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme); - - if (authenticationOptions.IsDebugTokenEnabled) - { - authBuilder.AddScheme(DebugTokenHandler.Schema, - options => { } - ); - - schemeSelector = context => - { - string debugHeader = context.Request.Headers[DebugTokenHandler.HeaderName]; - - return string.IsNullOrWhiteSpace(debugHeader) == false - ? DebugTokenHandler.Schema - : null; - }; - } - - authBuilder - .AddJwtBearer( - options => - { - options.TokenValidationParameters = new TokenValidationParameters - { - ValidateLifetime = true, - ValidateIssuer = false, - ValidateAudience = false, - ValidateIssuerSigningKey = true, - IssuerSigningKey = SigningHelper.GetPublicKey(authenticationOptions.PublicSigningKey), - ClockSkew = TimeSpan.Zero, - }; - - options.ForwardDefaultSelector = schemeSelector; - } - ); - } + } } } \ No newline at end of file diff --git a/JwtAuthentication.Core/TokenHandlers/DebugTokenHandler.cs b/JwtAuthentication.Core/TokenHandlers/DebugTokenHandler.cs deleted file mode 100644 index e585183..0000000 --- a/JwtAuthentication.Core/TokenHandlers/DebugTokenHandler.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Claims; -using System.Text; -using System.Text.Encodings.Web; -using System.Text.Json; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authentication; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.TokenHandlers -{ - internal class DebugTokenHandler : AuthenticationHandler - { - public const string Schema = "DebugTokenAuthentication"; - - public const string HeaderName = "X-DEBUG-TOKEN"; - - public DebugTokenHandler( - IOptionsMonitor options, - ILoggerFactory logger, - UrlEncoder encoder, - ISystemClock clock) - : base(options, - logger, - encoder, - clock - ) - { - } - - /// - /// Searches the 'Authorization' header for a 'DebugToken' token. If the 'DebugToken' token is found, it is decoded from - /// base64. - /// - /// - protected override Task HandleAuthenticateAsync() - { - // skip authentication if endpoint has [AllowAnonymous] attribute - var endpoint = Context.GetEndpoint(); - - if (endpoint?.Metadata?.GetMetadata() != null) - { - return Task.FromResult(AuthenticateResult.NoResult()); - } - - try - { - string token = Request.Headers[HeaderName]; - - if (string.IsNullOrEmpty(token)) - { - return Task.FromResult(AuthenticateResult.NoResult()); - } - - var base64EncodedBytes = Convert.FromBase64String(token); - var decodedToken = Encoding.UTF8.GetString(base64EncodedBytes); - - var claims = JsonSerializer.Deserialize>(decodedToken) - .SelectMany(x => x.Value.ValueKind == JsonValueKind.Array - ? x.Value.EnumerateArray().Select(e => (x.Key, value: e.GetString())) - : new[] { (x.Key, value: x.Value.GetString()) } - ) - .Select(x => new Claim(x.Key, x.value)) - .ToList(); - - var claimsIdentity = new ClaimsIdentity(claims, Scheme.Name); - var principal = new ClaimsPrincipal(claimsIdentity); - var ticket = new AuthenticationTicket(principal, Scheme.Name); - return Task.FromResult(AuthenticateResult.Success(ticket)); - } - catch (Exception ex) - { - Logger.LogError(ex, "An error while login through DebugToken Scheme"); - return Task.FromResult(AuthenticateResult.Fail(ex)); - } - } - } -} \ No newline at end of file From 7f3ad3473bc5ea6f6bfb6090936bb9ff28da3bac Mon Sep 17 00:00:00 2001 From: iamvladislove Date: Tue, 30 Aug 2022 14:36:02 +0500 Subject: [PATCH 29/34] chore: #60: adds a project example for presenting custom credentials validator --- AspNetCore.JwtAuthentication.sln | 7 +++ .../Controllers/ExampleController.cs | 32 +++++++++++++ .../CustomUserCredentialsValidator.cs | 16 +++++++ ...NetCore3.1.WithCredentialsValidator.csproj | 13 ++++++ .../Program.cs | 19 ++++++++ .../Properties/launchSettings.json | 30 +++++++++++++ .../Startup.cs | 45 +++++++++++++++++++ .../appsettings.json | 6 +++ .../Contracts/UserCredentialsValidator.cs | 10 +++++ 9 files changed, 178 insertions(+) create mode 100644 Examples/Example.NetCore.3.1.WithCredentialsValidator/Controllers/ExampleController.cs create mode 100644 Examples/Example.NetCore.3.1.WithCredentialsValidator/CustomUserCredentialsValidator.cs create mode 100644 Examples/Example.NetCore.3.1.WithCredentialsValidator/Example.NetCore3.1.WithCredentialsValidator.csproj create mode 100644 Examples/Example.NetCore.3.1.WithCredentialsValidator/Program.cs create mode 100644 Examples/Example.NetCore.3.1.WithCredentialsValidator/Properties/launchSettings.json create mode 100644 Examples/Example.NetCore.3.1.WithCredentialsValidator/Startup.cs create mode 100644 Examples/Example.NetCore.3.1.WithCredentialsValidator/appsettings.json create mode 100644 JwtAuthentication.Core/Contracts/UserCredentialsValidator.cs diff --git a/AspNetCore.JwtAuthentication.sln b/AspNetCore.JwtAuthentication.sln index 2d88c48..28bc42e 100644 --- a/AspNetCore.JwtAuthentication.sln +++ b/AspNetCore.JwtAuthentication.sln @@ -64,6 +64,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JwtAuthentication.Shared", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.NetCore3.1.PermissionBasedAuthentication", "Examples\Example.NetCore3.1.PermissionBasedAuthentication\Example.NetCore3.1.PermissionBasedAuthentication.csproj", "{7397D805-384D-4E60-A7BC-E650664231D0}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.NetCore3.1.WithCredentialsValidator", "Examples\Example.NetCore.3.1.WithCredentialsValidator\Example.NetCore3.1.WithCredentialsValidator.csproj", "{28A85E4F-20F1-48E2-A439-B2C84F06F242}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -166,6 +168,10 @@ Global {7397D805-384D-4E60-A7BC-E650664231D0}.Debug|Any CPU.Build.0 = Debug|Any CPU {7397D805-384D-4E60-A7BC-E650664231D0}.Release|Any CPU.ActiveCfg = Release|Any CPU {7397D805-384D-4E60-A7BC-E650664231D0}.Release|Any CPU.Build.0 = Release|Any CPU + {28A85E4F-20F1-48E2-A439-B2C84F06F242}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28A85E4F-20F1-48E2-A439-B2C84F06F242}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28A85E4F-20F1-48E2-A439-B2C84F06F242}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28A85E4F-20F1-48E2-A439-B2C84F06F242}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -195,6 +201,7 @@ Global {F0E28B79-7957-444F-B437-D2EEC072A6DE} = {7A925031-2656-4CEB-821A-D76739E0E5A2} {63E8464D-8489-4423-ADCD-1107DC5D9336} = {614DB4C6-A4BE-4BBF-B385-C34985CA1FC3} {7397D805-384D-4E60-A7BC-E650664231D0} = {614DB4C6-A4BE-4BBF-B385-C34985CA1FC3} + {28A85E4F-20F1-48E2-A439-B2C84F06F242} = {614DB4C6-A4BE-4BBF-B385-C34985CA1FC3} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C2026BF9-DACC-4EA4-AF04-B8A590EA38BF} diff --git a/Examples/Example.NetCore.3.1.WithCredentialsValidator/Controllers/ExampleController.cs b/Examples/Example.NetCore.3.1.WithCredentialsValidator/Controllers/ExampleController.cs new file mode 100644 index 0000000..bf8c3f1 --- /dev/null +++ b/Examples/Example.NetCore.3.1.WithCredentialsValidator/Controllers/ExampleController.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Example.NetCore3._1.WithCredentialsValidator.Controllers +{ + [ApiController] + [Route("[controller]")] + public class ExampleController : ControllerBase + { + private static readonly string[] Summaries = + { + "Freezing", + "Bracing", + "Chilly", + "Cool", + "Mild", + "Warm", + "Balmy", + "Hot", + "Sweltering", + "Scorching", + }; + + [Authorize] + [HttpGet] + public IEnumerable Get() + { + return Summaries; + } + } +} \ No newline at end of file diff --git a/Examples/Example.NetCore.3.1.WithCredentialsValidator/CustomUserCredentialsValidator.cs b/Examples/Example.NetCore.3.1.WithCredentialsValidator/CustomUserCredentialsValidator.cs new file mode 100644 index 0000000..93eda3c --- /dev/null +++ b/Examples/Example.NetCore.3.1.WithCredentialsValidator/CustomUserCredentialsValidator.cs @@ -0,0 +1,16 @@ +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contracts; + +namespace Example.NetCore3._1.WithCredentialsValidator +{ + public class CustomUserCredentialsValidator : UserCredentialsValidator + { + private const string Login = "User"; + private const string Password = "User"; + + public override Task ValidateUserCredentials(string login, string password) + { + return Task.FromResult(login == Login && password == Password); + } + } +} diff --git a/Examples/Example.NetCore.3.1.WithCredentialsValidator/Example.NetCore3.1.WithCredentialsValidator.csproj b/Examples/Example.NetCore.3.1.WithCredentialsValidator/Example.NetCore3.1.WithCredentialsValidator.csproj new file mode 100644 index 0000000..b72dbaf --- /dev/null +++ b/Examples/Example.NetCore.3.1.WithCredentialsValidator/Example.NetCore3.1.WithCredentialsValidator.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + Example.NetCore._3._1.WithCredentialsValidator + + + + + + + + diff --git a/Examples/Example.NetCore.3.1.WithCredentialsValidator/Program.cs b/Examples/Example.NetCore.3.1.WithCredentialsValidator/Program.cs new file mode 100644 index 0000000..8095828 --- /dev/null +++ b/Examples/Example.NetCore.3.1.WithCredentialsValidator/Program.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace Example.NetCore3._1.WithCredentialsValidator +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) + { + return Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); + } + } +} diff --git a/Examples/Example.NetCore.3.1.WithCredentialsValidator/Properties/launchSettings.json b/Examples/Example.NetCore.3.1.WithCredentialsValidator/Properties/launchSettings.json new file mode 100644 index 0000000..9eba533 --- /dev/null +++ b/Examples/Example.NetCore.3.1.WithCredentialsValidator/Properties/launchSettings.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:36212", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "example", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Example.NetCore3._1.WithCredentialsValidator": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "example", + "applicationUrl": "http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/Examples/Example.NetCore.3.1.WithCredentialsValidator/Startup.cs b/Examples/Example.NetCore.3.1.WithCredentialsValidator/Startup.cs new file mode 100644 index 0000000..4b60d25 --- /dev/null +++ b/Examples/Example.NetCore.3.1.WithCredentialsValidator/Startup.cs @@ -0,0 +1,45 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using TourmalineCore.AspNetCore.JwtAuthentication.Core; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; + +namespace Example.NetCore3._1.WithCredentialsValidator +{ + public class Startup + { + private readonly IConfiguration _configuration; + + public Startup(IConfiguration configuration) + { + _configuration = configuration; + } + + public void ConfigureServices(IServiceCollection services) + { + services + .AddJwtAuthentication(_configuration.GetSection(nameof(AuthenticationOptions)).Get()) + .AddUserCredentialValidator(); + + services.AddControllers(); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + + app + .UseDefaultLoginMiddleware() + .UseJwtAuthentication(); + + app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); + } + } +} diff --git a/Examples/Example.NetCore.3.1.WithCredentialsValidator/appsettings.json b/Examples/Example.NetCore.3.1.WithCredentialsValidator/appsettings.json new file mode 100644 index 0000000..8e261c5 --- /dev/null +++ b/Examples/Example.NetCore.3.1.WithCredentialsValidator/appsettings.json @@ -0,0 +1,6 @@ +{ + "AuthenticationOptions": { + "PublicSigningKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQAB", + "PrivateSigningKey": "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU" + } +} \ No newline at end of file diff --git a/JwtAuthentication.Core/Contracts/UserCredentialsValidator.cs b/JwtAuthentication.Core/Contracts/UserCredentialsValidator.cs new file mode 100644 index 0000000..c88197f --- /dev/null +++ b/JwtAuthentication.Core/Contracts/UserCredentialsValidator.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; + +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Contracts +{ + public abstract class UserCredentialsValidator : IUserCredentialsValidator + { + public abstract Task ValidateUserCredentials(string login, string password); + } +} From 1b51a86ea1470a10630720d87b610664210a66bb Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Wed, 31 Aug 2022 09:54:18 +0500 Subject: [PATCH 30/34] chore: #60: adds interface for authentication options --- .../Options/AuthenticationOptions.cs | 23 +++++++++++++++++-- .../Options/AuthenticationOptions.cs | 23 +++++++++++++++++-- .../AuthenticationExtensions.cs | 8 +++---- .../Options/BaseAuthenticationOptions.cs | 23 ------------------- .../Contracts/IAuthenticationOptions.cs | 17 ++++++++++++++ .../Services/TokenManager.cs | 6 ++--- .../TokenServices/JwtTokenCreator.cs | 6 ++--- .../TokenServices/JwtTokenValidator.cs | 6 ++--- 8 files changed, 72 insertions(+), 40 deletions(-) delete mode 100644 JwtAuthentication.Shared/Options/BaseAuthenticationOptions.cs create mode 100644 JwtAuthentication.Shared/Options/Contracts/IAuthenticationOptions.cs diff --git a/JwtAuthentication.Core/Options/AuthenticationOptions.cs b/JwtAuthentication.Core/Options/AuthenticationOptions.cs index a175469..9c8fbca 100644 --- a/JwtAuthentication.Core/Options/AuthenticationOptions.cs +++ b/JwtAuthentication.Core/Options/AuthenticationOptions.cs @@ -1,6 +1,25 @@ -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Options { - public class AuthenticationOptions : BaseAuthenticationOptions { } + public class AuthenticationOptions : IAuthenticationOptions + { + private int _accessTokenExpireInMinutes; + + public string PublicSigningKey { get; set; } + + public string PrivateSigningKey { get; set; } + + public string Issuer { get; set; } + + public string Audience { get; set; } + + public virtual int AccessTokenExpireInMinutes + { + get => _accessTokenExpireInMinutes == default ? 10080 : _accessTokenExpireInMinutes; + set => _accessTokenExpireInMinutes = value; + } + + public bool IsDebugTokenEnabled { get; set; } + } } \ No newline at end of file diff --git a/JwtAuthentication.Identity/Options/AuthenticationOptions.cs b/JwtAuthentication.Identity/Options/AuthenticationOptions.cs index d8354cb..1cbde28 100644 --- a/JwtAuthentication.Identity/Options/AuthenticationOptions.cs +++ b/JwtAuthentication.Identity/Options/AuthenticationOptions.cs @@ -1,6 +1,25 @@ -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options { - public class AuthenticationOptions : BaseAuthenticationOptions { } + public class AuthenticationOptions : IAuthenticationOptions + { + private int _accessTokenExpireInMinutes; + + public string PublicSigningKey { get; set; } + + public string PrivateSigningKey { get; set; } + + public string Issuer { get; set; } + + public string Audience { get; set; } + + public virtual int AccessTokenExpireInMinutes + { + get => _accessTokenExpireInMinutes == default ? 10080 : _accessTokenExpireInMinutes; + set => _accessTokenExpireInMinutes = value; + } + + public bool IsDebugTokenEnabled { get; set; } + } } \ No newline at end of file diff --git a/JwtAuthentication.Shared/AuthenticationExtensions.cs b/JwtAuthentication.Shared/AuthenticationExtensions.cs index 678a8fd..7203b2f 100644 --- a/JwtAuthentication.Shared/AuthenticationExtensions.cs +++ b/JwtAuthentication.Shared/AuthenticationExtensions.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Signing; @@ -27,7 +27,7 @@ public static class AuthenticationExtensions /// public static IServiceCollection AddJwtValidation( IServiceCollection services, - BaseAuthenticationOptions authenticationOptions) + IAuthenticationOptions authenticationOptions) { services.AddJwtBearer(authenticationOptions); @@ -42,7 +42,7 @@ public static IServiceCollection AddJwtValidation( /// public static IServiceCollection AddJwtAuthentication( this IServiceCollection services, - BaseAuthenticationOptions authenticationOptions) + IAuthenticationOptions authenticationOptions) { services.AddTransient(); services.AddTransient(); @@ -82,7 +82,7 @@ public static IServiceCollection WithUserClaimsProvider(ISe public static void AddJwtBearer( this IServiceCollection services, - BaseAuthenticationOptions authenticationOptions) + IAuthenticationOptions authenticationOptions) { services.AddSingleton(authenticationOptions); diff --git a/JwtAuthentication.Shared/Options/BaseAuthenticationOptions.cs b/JwtAuthentication.Shared/Options/BaseAuthenticationOptions.cs deleted file mode 100644 index 03e6760..0000000 --- a/JwtAuthentication.Shared/Options/BaseAuthenticationOptions.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options -{ - public class BaseAuthenticationOptions - { - private int _accessTokenExpireInMinutes; - - public string PublicSigningKey { get; set; } - - public string PrivateSigningKey { get; set; } - - public string Issuer { get; set; } - - public string Audience { get; set; } - - public virtual int AccessTokenExpireInMinutes - { - get => _accessTokenExpireInMinutes == default ? 10080 : _accessTokenExpireInMinutes; - set => _accessTokenExpireInMinutes = value; - } - - public bool IsDebugTokenEnabled { get; set; } - } -} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Options/Contracts/IAuthenticationOptions.cs b/JwtAuthentication.Shared/Options/Contracts/IAuthenticationOptions.cs new file mode 100644 index 0000000..0271431 --- /dev/null +++ b/JwtAuthentication.Shared/Options/Contracts/IAuthenticationOptions.cs @@ -0,0 +1,17 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts +{ + public interface IAuthenticationOptions + { + public string PrivateSigningKey { get; set; } + + public string PublicSigningKey { get; set; } + + public string Issuer { get; set; } + + public string Audience { get; set; } + + public int AccessTokenExpireInMinutes { get; set; } + + public bool IsDebugTokenEnabled { get; set; } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Services/TokenManager.cs b/JwtAuthentication.Shared/Services/TokenManager.cs index 72da1b6..f5ac5ea 100644 --- a/JwtAuthentication.Shared/Services/TokenManager.cs +++ b/JwtAuthentication.Shared/Services/TokenManager.cs @@ -3,7 +3,7 @@ using System.Security.Claims; using System.Threading.Tasks; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; @@ -14,12 +14,12 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services { public class TokenManager : ITokenManager { - private readonly BaseAuthenticationOptions _options; + private readonly IAuthenticationOptions _options; private readonly IUserClaimsProvider _userClaimsProvider; private readonly IJwtTokenCreator _jwtTokenCreator; public TokenManager( - BaseAuthenticationOptions options, + IAuthenticationOptions options, IUserClaimsProvider userClaimsProvider, IJwtTokenCreator jwtTokenCreator) { diff --git a/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs b/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs index a5a7be0..8d3798c 100644 --- a/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs +++ b/JwtAuthentication.Shared/TokenServices/JwtTokenCreator.cs @@ -5,7 +5,7 @@ using System.Security.Claims; using System.Threading.Tasks; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Signing; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; @@ -13,9 +13,9 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices { public class JwtTokenCreator : IJwtTokenCreator { - private readonly BaseAuthenticationOptions _authenticationOptions; + private readonly IAuthenticationOptions _authenticationOptions; - public JwtTokenCreator(BaseAuthenticationOptions authenticationOptions) + public JwtTokenCreator(IAuthenticationOptions authenticationOptions) { _authenticationOptions = authenticationOptions; } diff --git a/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs b/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs index 84b83b7..d70a262 100644 --- a/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs +++ b/JwtAuthentication.Shared/TokenServices/JwtTokenValidator.cs @@ -4,7 +4,7 @@ using System.Linq; using System.Threading.Tasks; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Signing; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; @@ -12,9 +12,9 @@ namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices { public class JwtTokenValidator : IJwtTokenValidator { - private readonly BaseAuthenticationOptions _authenticationOptions; + private readonly IAuthenticationOptions _authenticationOptions; - public JwtTokenValidator(BaseAuthenticationOptions options) + public JwtTokenValidator(IAuthenticationOptions options) { _authenticationOptions = options; } From 7210889eee1a80ad7b9fa0e8ac79348476341119 Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Wed, 31 Aug 2022 09:57:18 +0500 Subject: [PATCH 31/34] chore: #60: adds interface for the refresh endpoint options --- .../Options/RefreshEndpointOptions.cs | 13 +++++++++++-- .../Options/RefreshEndpointOptions.cs | 13 +++++++++++-- .../Options/BaseRefreshEndpointOptions.cs | 13 ------------- .../Options/Contracts/IRefreshEndpointOptions.cs | 7 +++++++ 4 files changed, 29 insertions(+), 17 deletions(-) delete mode 100644 JwtAuthentication.Shared/Options/BaseRefreshEndpointOptions.cs create mode 100644 JwtAuthentication.Shared/Options/Contracts/IRefreshEndpointOptions.cs diff --git a/JwtAuthentication.Core/Options/RefreshEndpointOptions.cs b/JwtAuthentication.Core/Options/RefreshEndpointOptions.cs index a30f402..18aa7eb 100644 --- a/JwtAuthentication.Core/Options/RefreshEndpointOptions.cs +++ b/JwtAuthentication.Core/Options/RefreshEndpointOptions.cs @@ -1,6 +1,15 @@ -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Options { - public class RefreshEndpointOptions : BaseRefreshEndpointOptions { } + public class RefreshEndpointOptions : IRefreshEndpointOptions + { + private string _refreshEndpointRoute; + + public string RefreshEndpointRoute + { + get => _refreshEndpointRoute ?? "/auth/refresh"; + set => _refreshEndpointRoute = value; + } + } } \ No newline at end of file diff --git a/JwtAuthentication.Identity/Options/RefreshEndpointOptions.cs b/JwtAuthentication.Identity/Options/RefreshEndpointOptions.cs index e4b4cf8..c5c69a8 100644 --- a/JwtAuthentication.Identity/Options/RefreshEndpointOptions.cs +++ b/JwtAuthentication.Identity/Options/RefreshEndpointOptions.cs @@ -1,6 +1,15 @@ -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; +using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Identity.Options { - public class RefreshEndpointOptions : BaseRefreshEndpointOptions { } + public class RefreshEndpointOptions : IRefreshEndpointOptions + { + private string _refreshEndpointRoute; + + public string RefreshEndpointRoute + { + get => _refreshEndpointRoute ?? "/auth/refresh"; + set => _refreshEndpointRoute = value; + } + } } \ No newline at end of file diff --git a/JwtAuthentication.Shared/Options/BaseRefreshEndpointOptions.cs b/JwtAuthentication.Shared/Options/BaseRefreshEndpointOptions.cs deleted file mode 100644 index 26af474..0000000 --- a/JwtAuthentication.Shared/Options/BaseRefreshEndpointOptions.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options -{ - public class BaseRefreshEndpointOptions - { - private string _refreshEndpointRoute; - - public string RefreshEndpointRoute - { - get => _refreshEndpointRoute ?? "/auth/refresh"; - set => _refreshEndpointRoute = value; - } - } -} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Options/Contracts/IRefreshEndpointOptions.cs b/JwtAuthentication.Shared/Options/Contracts/IRefreshEndpointOptions.cs new file mode 100644 index 0000000..6e50bc3 --- /dev/null +++ b/JwtAuthentication.Shared/Options/Contracts/IRefreshEndpointOptions.cs @@ -0,0 +1,7 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts +{ + public interface IRefreshEndpointOptions + { + public string RefreshEndpointRoute { get; set; } + } +} From a6b8159b76445097f80ba85bfd300d51975e0622 Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Wed, 31 Aug 2022 10:11:07 +0500 Subject: [PATCH 32/34] chore: #60: removes unnecessary options from the shared project --- .../Options/RefreshTokenOptions.cs | 13 ++++++++++--- .../Services/CoreRefreshService.cs | 2 +- .../Options/BaseCookieAuthOptions.cs | 9 --------- .../Options/BaseLoginEndpointOptions.cs | 15 --------------- .../Options/BaseRefreshTokenOptions.cs | 13 ------------- 5 files changed, 11 insertions(+), 41 deletions(-) delete mode 100644 JwtAuthentication.Shared/Options/BaseCookieAuthOptions.cs delete mode 100644 JwtAuthentication.Shared/Options/BaseLoginEndpointOptions.cs delete mode 100644 JwtAuthentication.Shared/Options/BaseRefreshTokenOptions.cs diff --git a/JwtAuthentication.Core/Options/RefreshTokenOptions.cs b/JwtAuthentication.Core/Options/RefreshTokenOptions.cs index b661866..a661b11 100644 --- a/JwtAuthentication.Core/Options/RefreshTokenOptions.cs +++ b/JwtAuthentication.Core/Options/RefreshTokenOptions.cs @@ -1,6 +1,13 @@ -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options; - namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Options { - public class RefreshTokenOptions : BaseRefreshTokenOptions { } + public class RefreshTokenOptions + { + private int _refreshTokenExpireInMinutes; + + public int RefreshTokenExpireInMinutes + { + get => _refreshTokenExpireInMinutes == default ? 10080 : _refreshTokenExpireInMinutes; + set => _refreshTokenExpireInMinutes = value; + } + } } diff --git a/JwtAuthentication.Core/Services/CoreRefreshService.cs b/JwtAuthentication.Core/Services/CoreRefreshService.cs index 8c5da08..767dee0 100644 --- a/JwtAuthentication.Core/Services/CoreRefreshService.cs +++ b/JwtAuthentication.Core/Services/CoreRefreshService.cs @@ -16,7 +16,7 @@ internal class CoreRefreshService : ICoreRefreshService public CoreRefreshService( IJwtTokenValidator jwtTokenValidator, - IJwtTokenCreator jwtTokenCreator, + IJwtTokenCreator jwtTokenCreator, RefreshTokenOptions refreshTokenOptions) { _jwtTokenValidator = jwtTokenValidator; diff --git a/JwtAuthentication.Shared/Options/BaseCookieAuthOptions.cs b/JwtAuthentication.Shared/Options/BaseCookieAuthOptions.cs deleted file mode 100644 index 5802a3f..0000000 --- a/JwtAuthentication.Shared/Options/BaseCookieAuthOptions.cs +++ /dev/null @@ -1,9 +0,0 @@ -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options -{ - public class BaseCookieAuthOptions : ICookieAuthOptions - { - public string Key { get; set; } - } -} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Options/BaseLoginEndpointOptions.cs b/JwtAuthentication.Shared/Options/BaseLoginEndpointOptions.cs deleted file mode 100644 index f806c26..0000000 --- a/JwtAuthentication.Shared/Options/BaseLoginEndpointOptions.cs +++ /dev/null @@ -1,15 +0,0 @@ -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options.Contracts; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options -{ - public class BaseLoginEndpointOptions : ILoginEndpointOptions - { - private string _loginEndpointRoute; - - public string LoginEndpointRoute - { - get => _loginEndpointRoute ?? "/auth/login"; - set => _loginEndpointRoute = value; - } - } -} \ No newline at end of file diff --git a/JwtAuthentication.Shared/Options/BaseRefreshTokenOptions.cs b/JwtAuthentication.Shared/Options/BaseRefreshTokenOptions.cs deleted file mode 100644 index 420bab2..0000000 --- a/JwtAuthentication.Shared/Options/BaseRefreshTokenOptions.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Options -{ - public class BaseRefreshTokenOptions - { - private int _refreshTokenExpireInMinutes; - - public int RefreshTokenExpireInMinutes - { - get => _refreshTokenExpireInMinutes == default ? 10080 : _refreshTokenExpireInMinutes; - set => _refreshTokenExpireInMinutes = value; - } - } -} From a741a9acf66393eea4fc68423f32cd27b4ce3f92 Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Wed, 31 Aug 2022 10:42:58 +0500 Subject: [PATCH 33/34] chore: #60: moves internal classes in the core project into a separate folder --- JwtAuthentication.Core/ApplicationBuilderExtension.cs | 1 + JwtAuthentication.Core/AuthenticationExtensions.cs | 6 ++---- JwtAuthentication.Core/Consts.cs | 7 ------- .../Middlewares/Refresh/RefreshMiddleware.cs | 6 +++--- .../Middlewares/Refresh/RefreshMiddlewareBuilder.cs | 5 +++-- .../Models/Requests/CoreRefreshTokenRequestModel.cs | 7 +++++++ .../Services/Contracts/ICoreRefreshService.cs | 2 +- .../Services/Contracts/ICoreRefreshTokenManager.cs | 2 +- .../{ => Internal}/Services/CoreRefreshService.cs | 4 ++-- .../{ => Internal}/Services/CoreRefreshTokenManager.cs | 4 ++-- .../{ => Internal}/Services/LoginWithRefreshService.cs | 4 ++-- .../Models/Requests/CoreRefreshTokenRequestModel.cs | 7 ------- JwtAuthentication.Core/Models/TokenModel.cs | 8 -------- 13 files changed, 24 insertions(+), 39 deletions(-) delete mode 100644 JwtAuthentication.Core/Consts.cs rename JwtAuthentication.Core/{ => Internal}/Middlewares/Refresh/RefreshMiddleware.cs (90%) rename JwtAuthentication.Core/{ => Internal}/Middlewares/Refresh/RefreshMiddlewareBuilder.cs (91%) create mode 100644 JwtAuthentication.Core/Internal/Models/Requests/CoreRefreshTokenRequestModel.cs rename JwtAuthentication.Core/{ => Internal}/Services/Contracts/ICoreRefreshService.cs (72%) rename JwtAuthentication.Core/{ => Internal}/Services/Contracts/ICoreRefreshTokenManager.cs (71%) rename JwtAuthentication.Core/{ => Internal}/Services/CoreRefreshService.cs (90%) rename JwtAuthentication.Core/{ => Internal}/Services/CoreRefreshTokenManager.cs (85%) rename JwtAuthentication.Core/{ => Internal}/Services/LoginWithRefreshService.cs (89%) delete mode 100644 JwtAuthentication.Core/Models/Requests/CoreRefreshTokenRequestModel.cs delete mode 100644 JwtAuthentication.Core/Models/TokenModel.cs diff --git a/JwtAuthentication.Core/ApplicationBuilderExtension.cs b/JwtAuthentication.Core/ApplicationBuilderExtension.cs index 66b8082..497aee2 100644 --- a/JwtAuthentication.Core/ApplicationBuilderExtension.cs +++ b/JwtAuthentication.Core/ApplicationBuilderExtension.cs @@ -1,6 +1,7 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Internal.Middlewares.Refresh; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; diff --git a/JwtAuthentication.Core/AuthenticationExtensions.cs b/JwtAuthentication.Core/AuthenticationExtensions.cs index f96f7dc..e29aad5 100644 --- a/JwtAuthentication.Core/AuthenticationExtensions.cs +++ b/JwtAuthentication.Core/AuthenticationExtensions.cs @@ -1,15 +1,13 @@ using Microsoft.Extensions.DependencyInjection; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Filters; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; using AuthenticationOptions = TourmalineCore.AspNetCore.JwtAuthentication.Core.Options.AuthenticationOptions; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Contracts; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Internal.Services; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Internal.Services.Contracts; namespace TourmalineCore.AspNetCore.JwtAuthentication.Core { diff --git a/JwtAuthentication.Core/Consts.cs b/JwtAuthentication.Core/Consts.cs deleted file mode 100644 index 8d0d780..0000000 --- a/JwtAuthentication.Core/Consts.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core -{ - public static class Consts - { - public const string TokenTypeClaimName = "tokenType"; - } -} diff --git a/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs b/JwtAuthentication.Core/Internal/Middlewares/Refresh/RefreshMiddleware.cs similarity index 90% rename from JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs rename to JwtAuthentication.Core/Internal/Middlewares/Refresh/RefreshMiddleware.cs index fdec721..cab19ce 100644 --- a/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddleware.cs +++ b/JwtAuthentication.Core/Internal/Middlewares/Refresh/RefreshMiddleware.cs @@ -2,14 +2,14 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Internal.Models.Requests; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Internal.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Requests; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Middlewares; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Internal.Middlewares.Refresh { internal class RefreshMiddleware : RequestMiddlewareBase { diff --git a/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddlewareBuilder.cs b/JwtAuthentication.Core/Internal/Middlewares/Refresh/RefreshMiddlewareBuilder.cs similarity index 91% rename from JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddlewareBuilder.cs rename to JwtAuthentication.Core/Internal/Middlewares/Refresh/RefreshMiddlewareBuilder.cs index e63fefc..f736a2a 100644 --- a/JwtAuthentication.Core/Middlewares/Refresh/RefreshMiddlewareBuilder.cs +++ b/JwtAuthentication.Core/Internal/Middlewares/Refresh/RefreshMiddlewareBuilder.cs @@ -1,12 +1,13 @@ using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Refresh +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Internal.Middlewares.Refresh { - public class RefreshMiddlewareBuilder : IRefreshMiddlewareBuilder + internal class RefreshMiddlewareBuilder : IRefreshMiddlewareBuilder { private static Func _onRefreshExecutingCallback = s => Task.CompletedTask; private static Func _onRefreshExecutedCallback = s => Task.CompletedTask; diff --git a/JwtAuthentication.Core/Internal/Models/Requests/CoreRefreshTokenRequestModel.cs b/JwtAuthentication.Core/Internal/Models/Requests/CoreRefreshTokenRequestModel.cs new file mode 100644 index 0000000..527bb15 --- /dev/null +++ b/JwtAuthentication.Core/Internal/Models/Requests/CoreRefreshTokenRequestModel.cs @@ -0,0 +1,7 @@ +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Internal.Models.Requests +{ + internal class CoreRefreshTokenRequestModel + { + public string RefreshTokenValue { get; set; } + } +} \ No newline at end of file diff --git a/JwtAuthentication.Core/Services/Contracts/ICoreRefreshService.cs b/JwtAuthentication.Core/Internal/Services/Contracts/ICoreRefreshService.cs similarity index 72% rename from JwtAuthentication.Core/Services/Contracts/ICoreRefreshService.cs rename to JwtAuthentication.Core/Internal/Services/Contracts/ICoreRefreshService.cs index db6674a..90c59bf 100644 --- a/JwtAuthentication.Core/Services/Contracts/ICoreRefreshService.cs +++ b/JwtAuthentication.Core/Internal/Services/Contracts/ICoreRefreshService.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Internal.Services.Contracts { internal interface ICoreRefreshService { diff --git a/JwtAuthentication.Core/Services/Contracts/ICoreRefreshTokenManager.cs b/JwtAuthentication.Core/Internal/Services/Contracts/ICoreRefreshTokenManager.cs similarity index 71% rename from JwtAuthentication.Core/Services/Contracts/ICoreRefreshTokenManager.cs rename to JwtAuthentication.Core/Internal/Services/Contracts/ICoreRefreshTokenManager.cs index dcc86dd..dfc6b8c 100644 --- a/JwtAuthentication.Core/Services/Contracts/ICoreRefreshTokenManager.cs +++ b/JwtAuthentication.Core/Internal/Services/Contracts/ICoreRefreshTokenManager.cs @@ -1,7 +1,7 @@ using System.Threading.Tasks; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Internal.Services.Contracts { internal interface ICoreRefreshTokenManager { diff --git a/JwtAuthentication.Core/Services/CoreRefreshService.cs b/JwtAuthentication.Core/Internal/Services/CoreRefreshService.cs similarity index 90% rename from JwtAuthentication.Core/Services/CoreRefreshService.cs rename to JwtAuthentication.Core/Internal/Services/CoreRefreshService.cs index 767dee0..e9870fb 100644 --- a/JwtAuthentication.Core/Services/CoreRefreshService.cs +++ b/JwtAuthentication.Core/Internal/Services/CoreRefreshService.cs @@ -1,12 +1,12 @@ using System; using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Internal.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Errors; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Internal.Services { internal class CoreRefreshService : ICoreRefreshService { diff --git a/JwtAuthentication.Core/Services/CoreRefreshTokenManager.cs b/JwtAuthentication.Core/Internal/Services/CoreRefreshTokenManager.cs similarity index 85% rename from JwtAuthentication.Core/Services/CoreRefreshTokenManager.cs rename to JwtAuthentication.Core/Internal/Services/CoreRefreshTokenManager.cs index 526b38a..2e3fec3 100644 --- a/JwtAuthentication.Core/Services/CoreRefreshTokenManager.cs +++ b/JwtAuthentication.Core/Internal/Services/CoreRefreshTokenManager.cs @@ -1,10 +1,10 @@ using System.Threading.Tasks; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Internal.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.TokenServices.Contracts; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Internal.Services { internal class CoreRefreshTokenManager : ICoreRefreshTokenManager { diff --git a/JwtAuthentication.Core/Services/LoginWithRefreshService.cs b/JwtAuthentication.Core/Internal/Services/LoginWithRefreshService.cs similarity index 89% rename from JwtAuthentication.Core/Services/LoginWithRefreshService.cs rename to JwtAuthentication.Core/Internal/Services/LoginWithRefreshService.cs index 6a1b5b9..bf644e4 100644 --- a/JwtAuthentication.Core/Services/LoginWithRefreshService.cs +++ b/JwtAuthentication.Core/Internal/Services/LoginWithRefreshService.cs @@ -1,12 +1,12 @@ using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Services.Contracts; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Internal.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Requests; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models.Responses; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Services.Contracts; using TourmalineCore.AspNetCore.JwtAuthentication.Shared.UserServices.Contracts; -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Services +namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Internal.Services { internal class LoginWithRefreshService : LoginService { diff --git a/JwtAuthentication.Core/Models/Requests/CoreRefreshTokenRequestModel.cs b/JwtAuthentication.Core/Models/Requests/CoreRefreshTokenRequestModel.cs deleted file mode 100644 index 3b3688f..0000000 --- a/JwtAuthentication.Core/Models/Requests/CoreRefreshTokenRequestModel.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Models.Requests -{ - public class CoreRefreshTokenRequestModel - { - public string RefreshTokenValue { get; set; } - } -} \ No newline at end of file diff --git a/JwtAuthentication.Core/Models/TokenModel.cs b/JwtAuthentication.Core/Models/TokenModel.cs deleted file mode 100644 index ae33eca..0000000 --- a/JwtAuthentication.Core/Models/TokenModel.cs +++ /dev/null @@ -1,8 +0,0 @@ -using TourmalineCore.AspNetCore.JwtAuthentication.Shared.Models; - -namespace TourmalineCore.AspNetCore.JwtAuthentication.Core.Models -{ - public class TokenModel : BaseTokenModel - { - } -} From 6514bf5f55a5f76f79adc901409f36f04b1cde37 Mon Sep 17 00:00:00 2001 From: Vladislav Yusupov Date: Wed, 31 Aug 2022 11:49:43 +0500 Subject: [PATCH 34/34] chore: #60: changes the examples folder structure for .netcore3.1 projects --- AspNetCore.JwtAuthentication.sln | 61 ++++++------ .../Controllers/ExampleController.cs | 0 .../CustomUserCredentialsValidator.cs | 0 ...NetCore3.1.WithCredentialsValidator.csproj | 2 +- .../Program.cs | 0 .../Properties/launchSettings.json | 0 .../Startup.cs | 0 .../appsettings.json | 0 .../Controllers/ExampleController.cs | 0 ...e3.1.AuthenticationWithRefreshToken.csproj | 2 +- .../Program.cs | 0 .../Properties/launchSettings.json | 0 .../Startup.cs | 0 .../appsettings.json | 0 .../Controllers/ExampleController.cs | 0 ...ample.NetCore3.1.BaseAuthentication.csproj | 13 +++ .../Program.cs | 38 ++++---- .../Properties/launchSettings.json | 30 ++++++ .../Startup.cs | 43 ++++++++ .../appsettings.json | 0 .../Controllers/ExampleController.cs | 0 .../CustomUserClaimsProvider.cs | 0 ...re3.1.PermissionBasedAuthentication.csproj | 2 +- .../Program.cs | 0 .../Properties/launchSettings.json | 0 .../Startup.cs | 0 .../appsettings.json | 6 ++ ...ample.NetCore3.1.BaseAuthentication.csproj | 20 ---- .../Properties/launchSettings.json | 27 ------ .../Startup.cs | 97 ------------------- .../appsettings.json | 6 -- 31 files changed, 146 insertions(+), 201 deletions(-) rename Examples/{ => Core/NetCore3.1}/Example.NetCore.3.1.WithCredentialsValidator/Controllers/ExampleController.cs (100%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore.3.1.WithCredentialsValidator/CustomUserCredentialsValidator.cs (100%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore.3.1.WithCredentialsValidator/Example.NetCore3.1.WithCredentialsValidator.csproj (69%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore.3.1.WithCredentialsValidator/Program.cs (100%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore.3.1.WithCredentialsValidator/Properties/launchSettings.json (100%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore.3.1.WithCredentialsValidator/Startup.cs (100%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore.3.1.WithCredentialsValidator/appsettings.json (100%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore3.1.AuthenticationWithRefreshToken/Controllers/ExampleController.cs (100%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore3.1.AuthenticationWithRefreshToken/Example.NetCore3.1.AuthenticationWithRefreshToken.csproj (69%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore3.1.AuthenticationWithRefreshToken/Program.cs (100%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore3.1.AuthenticationWithRefreshToken/Properties/launchSettings.json (100%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore3.1.AuthenticationWithRefreshToken/Startup.cs (100%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore3.1.AuthenticationWithRefreshToken/appsettings.json (100%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore3.1.BaseAuthentication/Controllers/ExampleController.cs (100%) create mode 100644 Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Example.NetCore3.1.BaseAuthentication.csproj rename Examples/{ => Core/NetCore3.1}/Example.NetCore3.1.BaseAuthentication/Program.cs (96%) create mode 100644 Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Properties/launchSettings.json create mode 100644 Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Startup.cs rename Examples/{Example.NetCore3.1.PermissionBasedAuthentication => Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication}/appsettings.json (100%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore3.1.PermissionBasedAuthentication/Controllers/ExampleController.cs (100%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore3.1.PermissionBasedAuthentication/CustomUserClaimsProvider.cs (100%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore3.1.PermissionBasedAuthentication/Example.NetCore3.1.PermissionBasedAuthentication.csproj (69%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore3.1.PermissionBasedAuthentication/Program.cs (100%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore3.1.PermissionBasedAuthentication/Properties/launchSettings.json (100%) rename Examples/{ => Core/NetCore3.1}/Example.NetCore3.1.PermissionBasedAuthentication/Startup.cs (100%) create mode 100644 Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/appsettings.json delete mode 100644 Examples/Example.NetCore3.1.BaseAuthentication/Example.NetCore3.1.BaseAuthentication.csproj delete mode 100644 Examples/Example.NetCore3.1.BaseAuthentication/Properties/launchSettings.json delete mode 100644 Examples/Example.NetCore3.1.BaseAuthentication/Startup.cs delete mode 100644 Examples/Example.NetCore3.1.BaseAuthentication/appsettings.json diff --git a/AspNetCore.JwtAuthentication.sln b/AspNetCore.JwtAuthentication.sln index 28bc42e..b6af777 100644 --- a/AspNetCore.JwtAuthentication.sln +++ b/AspNetCore.JwtAuthentication.sln @@ -18,8 +18,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore5.0.Permissi EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore5.0.WithCredentialsValidator", "Examples\Example.NetCore5.0.WithCredentialsValidator\Example.NetCore5.0.WithCredentialsValidator.csproj", "{E2BC2C97-161E-41E4-B224-DFC62AD56768}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore3.1.BaseAuthentication", "Examples\Example.NetCore3.1.BaseAuthentication\Example.NetCore3.1.BaseAuthentication.csproj", "{43D3813D-CD36-46A7-86EF-CD6CF0A9A9BC}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore5.0.CookiesBasedAuthentication", "Examples\Example.NetCore5.0.CookiesBasedAuthentication\Example.NetCore5.0.CookiesBasedAuthentication.csproj", "{32E74378-AAF5-4CA6-8633-30997453E58A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JwtAuthentication.Identity", "JwtAuthentication.Identity\JwtAuthentication.Identity.csproj", "{60A8C4FC-D6DC-4C5B-9FA9-6F81F55F3667}" @@ -36,8 +34,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore6.0.BaseAuth EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NetCore5.0", "NetCore5.0", "{7A925031-2656-4CEB-821A-D76739E0E5A2}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NetCore3.", "NetCore3.", "{614DB4C6-A4BE-4BBF-B385-C34985CA1FC3}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NetCore6.0", "NetCore6.0", "{4FF83CB3-A634-4D07-BEE0-B5391B86F071}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore6.0.AuthenticationUsingIdentityUser", "Examples\Example.NetCore6.0.AuthenticationUsingIdentityUser\Example.NetCore6.0.AuthenticationUsingIdentityUser.csproj", "{28707296-5273-471B-89FB-FA3D6C62CA67}" @@ -58,13 +54,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore6.0.RefreshT EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore5.0.RefreshTokenWithConfidenceInterval", "Examples\Example.NetCore5.0.RefreshTokenWithConfidenceInterval\Example.NetCore5.0.RefreshTokenWithConfidenceInterval.csproj", "{F0E28B79-7957-444F-B437-D2EEC072A6DE}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore3.1.AuthenticationWithRefreshToken", "Examples\Example.NetCore3.1.AuthenticationWithRefreshToken\Example.NetCore3.1.AuthenticationWithRefreshToken.csproj", "{63E8464D-8489-4423-ADCD-1107DC5D9336}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JwtAuthentication.Shared", "JwtAuthentication.Shared\JwtAuthentication.Shared.csproj", "{E1952561-A7CD-45C3-B9D0-AC9B92A194CC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.NetCore3.1.PermissionBasedAuthentication", "Examples\Example.NetCore3.1.PermissionBasedAuthentication\Example.NetCore3.1.PermissionBasedAuthentication.csproj", "{7397D805-384D-4E60-A7BC-E650664231D0}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{D7304D43-BEFB-418C-866B-BCDBF4944DAE}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NetCore3.1", "NetCore3.1", "{89FFB48D-FF56-4FC0-BB01-47855CD3A1A0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore3.1.WithCredentialsValidator", "Examples\Core\NetCore3.1\Example.NetCore.3.1.WithCredentialsValidator\Example.NetCore3.1.WithCredentialsValidator.csproj", "{A092BCEE-7B25-4DFB-9DB7-D29399750095}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore3.1.AuthenticationWithRefreshToken", "Examples\Core\NetCore3.1\Example.NetCore3.1.AuthenticationWithRefreshToken\Example.NetCore3.1.AuthenticationWithRefreshToken.csproj", "{2B5AEDED-B2D5-45C1-865E-FEC5C62E7B6C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore3.1.BaseAuthentication", "Examples\Core\NetCore3.1\Example.NetCore3.1.BaseAuthentication\Example.NetCore3.1.BaseAuthentication.csproj", "{996BF68D-03EB-466D-8E79-CFEBD13D255D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example.NetCore3.1.WithCredentialsValidator", "Examples\Example.NetCore.3.1.WithCredentialsValidator\Example.NetCore3.1.WithCredentialsValidator.csproj", "{28A85E4F-20F1-48E2-A439-B2C84F06F242}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example.NetCore3.1.PermissionBasedAuthentication", "Examples\Core\NetCore3.1\Example.NetCore3.1.PermissionBasedAuthentication\Example.NetCore3.1.PermissionBasedAuthentication.csproj", "{47427766-B40C-4C8C-80F4-4EFD57AABBE0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -88,10 +90,6 @@ Global {E2BC2C97-161E-41E4-B224-DFC62AD56768}.Debug|Any CPU.Build.0 = Debug|Any CPU {E2BC2C97-161E-41E4-B224-DFC62AD56768}.Release|Any CPU.ActiveCfg = Release|Any CPU {E2BC2C97-161E-41E4-B224-DFC62AD56768}.Release|Any CPU.Build.0 = Release|Any CPU - {43D3813D-CD36-46A7-86EF-CD6CF0A9A9BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {43D3813D-CD36-46A7-86EF-CD6CF0A9A9BC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {43D3813D-CD36-46A7-86EF-CD6CF0A9A9BC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {43D3813D-CD36-46A7-86EF-CD6CF0A9A9BC}.Release|Any CPU.Build.0 = Release|Any CPU {32E74378-AAF5-4CA6-8633-30997453E58A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {32E74378-AAF5-4CA6-8633-30997453E58A}.Debug|Any CPU.Build.0 = Debug|Any CPU {32E74378-AAF5-4CA6-8633-30997453E58A}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -156,22 +154,26 @@ Global {F0E28B79-7957-444F-B437-D2EEC072A6DE}.Debug|Any CPU.Build.0 = Debug|Any CPU {F0E28B79-7957-444F-B437-D2EEC072A6DE}.Release|Any CPU.ActiveCfg = Release|Any CPU {F0E28B79-7957-444F-B437-D2EEC072A6DE}.Release|Any CPU.Build.0 = Release|Any CPU - {63E8464D-8489-4423-ADCD-1107DC5D9336}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {63E8464D-8489-4423-ADCD-1107DC5D9336}.Debug|Any CPU.Build.0 = Debug|Any CPU - {63E8464D-8489-4423-ADCD-1107DC5D9336}.Release|Any CPU.ActiveCfg = Release|Any CPU - {63E8464D-8489-4423-ADCD-1107DC5D9336}.Release|Any CPU.Build.0 = Release|Any CPU {E1952561-A7CD-45C3-B9D0-AC9B92A194CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E1952561-A7CD-45C3-B9D0-AC9B92A194CC}.Debug|Any CPU.Build.0 = Debug|Any CPU {E1952561-A7CD-45C3-B9D0-AC9B92A194CC}.Release|Any CPU.ActiveCfg = Release|Any CPU {E1952561-A7CD-45C3-B9D0-AC9B92A194CC}.Release|Any CPU.Build.0 = Release|Any CPU - {7397D805-384D-4E60-A7BC-E650664231D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7397D805-384D-4E60-A7BC-E650664231D0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7397D805-384D-4E60-A7BC-E650664231D0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7397D805-384D-4E60-A7BC-E650664231D0}.Release|Any CPU.Build.0 = Release|Any CPU - {28A85E4F-20F1-48E2-A439-B2C84F06F242}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {28A85E4F-20F1-48E2-A439-B2C84F06F242}.Debug|Any CPU.Build.0 = Debug|Any CPU - {28A85E4F-20F1-48E2-A439-B2C84F06F242}.Release|Any CPU.ActiveCfg = Release|Any CPU - {28A85E4F-20F1-48E2-A439-B2C84F06F242}.Release|Any CPU.Build.0 = Release|Any CPU + {A092BCEE-7B25-4DFB-9DB7-D29399750095}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A092BCEE-7B25-4DFB-9DB7-D29399750095}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A092BCEE-7B25-4DFB-9DB7-D29399750095}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A092BCEE-7B25-4DFB-9DB7-D29399750095}.Release|Any CPU.Build.0 = Release|Any CPU + {2B5AEDED-B2D5-45C1-865E-FEC5C62E7B6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2B5AEDED-B2D5-45C1-865E-FEC5C62E7B6C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2B5AEDED-B2D5-45C1-865E-FEC5C62E7B6C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2B5AEDED-B2D5-45C1-865E-FEC5C62E7B6C}.Release|Any CPU.Build.0 = Release|Any CPU + {996BF68D-03EB-466D-8E79-CFEBD13D255D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {996BF68D-03EB-466D-8E79-CFEBD13D255D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {996BF68D-03EB-466D-8E79-CFEBD13D255D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {996BF68D-03EB-466D-8E79-CFEBD13D255D}.Release|Any CPU.Build.0 = Release|Any CPU + {47427766-B40C-4C8C-80F4-4EFD57AABBE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {47427766-B40C-4C8C-80F4-4EFD57AABBE0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {47427766-B40C-4C8C-80F4-4EFD57AABBE0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {47427766-B40C-4C8C-80F4-4EFD57AABBE0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -180,7 +182,6 @@ Global {36F676C3-2C5F-4727-8BE2-8F759C2A3FBE} = {7A925031-2656-4CEB-821A-D76739E0E5A2} {51E0C282-0942-4367-95EB-F248E80A5D6F} = {7A925031-2656-4CEB-821A-D76739E0E5A2} {E2BC2C97-161E-41E4-B224-DFC62AD56768} = {7A925031-2656-4CEB-821A-D76739E0E5A2} - {43D3813D-CD36-46A7-86EF-CD6CF0A9A9BC} = {614DB4C6-A4BE-4BBF-B385-C34985CA1FC3} {32E74378-AAF5-4CA6-8633-30997453E58A} = {7A925031-2656-4CEB-821A-D76739E0E5A2} {1DF1D001-0194-4CD8-82DD-40AF57FC1432} = {7A925031-2656-4CEB-821A-D76739E0E5A2} {12915347-991A-4EA0-983D-03121E1C527B} = {7A925031-2656-4CEB-821A-D76739E0E5A2} @@ -188,7 +189,6 @@ Global {EF8EF2D5-9483-400E-B938-ADDB467BF300} = {ADBF0A06-FF69-40A6-8F32-2F188AE1B6A4} {DDA26737-950C-4B23-B66A-1733FB482A29} = {4FF83CB3-A634-4D07-BEE0-B5391B86F071} {7A925031-2656-4CEB-821A-D76739E0E5A2} = {ADBF0A06-FF69-40A6-8F32-2F188AE1B6A4} - {614DB4C6-A4BE-4BBF-B385-C34985CA1FC3} = {ADBF0A06-FF69-40A6-8F32-2F188AE1B6A4} {4FF83CB3-A634-4D07-BEE0-B5391B86F071} = {ADBF0A06-FF69-40A6-8F32-2F188AE1B6A4} {28707296-5273-471B-89FB-FA3D6C62CA67} = {4FF83CB3-A634-4D07-BEE0-B5391B86F071} {5AE1CC8C-80A2-46AF-A02E-BE129080F489} = {4FF83CB3-A634-4D07-BEE0-B5391B86F071} @@ -199,9 +199,12 @@ Global {C617F7DD-6E7E-4B5D-8766-C82C37EFFF6E} = {4FF83CB3-A634-4D07-BEE0-B5391B86F071} {ABDD94F3-DF9E-47B2-813F-935C54C8DEA7} = {4FF83CB3-A634-4D07-BEE0-B5391B86F071} {F0E28B79-7957-444F-B437-D2EEC072A6DE} = {7A925031-2656-4CEB-821A-D76739E0E5A2} - {63E8464D-8489-4423-ADCD-1107DC5D9336} = {614DB4C6-A4BE-4BBF-B385-C34985CA1FC3} - {7397D805-384D-4E60-A7BC-E650664231D0} = {614DB4C6-A4BE-4BBF-B385-C34985CA1FC3} - {28A85E4F-20F1-48E2-A439-B2C84F06F242} = {614DB4C6-A4BE-4BBF-B385-C34985CA1FC3} + {D7304D43-BEFB-418C-866B-BCDBF4944DAE} = {ADBF0A06-FF69-40A6-8F32-2F188AE1B6A4} + {89FFB48D-FF56-4FC0-BB01-47855CD3A1A0} = {D7304D43-BEFB-418C-866B-BCDBF4944DAE} + {A092BCEE-7B25-4DFB-9DB7-D29399750095} = {89FFB48D-FF56-4FC0-BB01-47855CD3A1A0} + {2B5AEDED-B2D5-45C1-865E-FEC5C62E7B6C} = {89FFB48D-FF56-4FC0-BB01-47855CD3A1A0} + {996BF68D-03EB-466D-8E79-CFEBD13D255D} = {89FFB48D-FF56-4FC0-BB01-47855CD3A1A0} + {47427766-B40C-4C8C-80F4-4EFD57AABBE0} = {89FFB48D-FF56-4FC0-BB01-47855CD3A1A0} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C2026BF9-DACC-4EA4-AF04-B8A590EA38BF} diff --git a/Examples/Example.NetCore.3.1.WithCredentialsValidator/Controllers/ExampleController.cs b/Examples/Core/NetCore3.1/Example.NetCore.3.1.WithCredentialsValidator/Controllers/ExampleController.cs similarity index 100% rename from Examples/Example.NetCore.3.1.WithCredentialsValidator/Controllers/ExampleController.cs rename to Examples/Core/NetCore3.1/Example.NetCore.3.1.WithCredentialsValidator/Controllers/ExampleController.cs diff --git a/Examples/Example.NetCore.3.1.WithCredentialsValidator/CustomUserCredentialsValidator.cs b/Examples/Core/NetCore3.1/Example.NetCore.3.1.WithCredentialsValidator/CustomUserCredentialsValidator.cs similarity index 100% rename from Examples/Example.NetCore.3.1.WithCredentialsValidator/CustomUserCredentialsValidator.cs rename to Examples/Core/NetCore3.1/Example.NetCore.3.1.WithCredentialsValidator/CustomUserCredentialsValidator.cs diff --git a/Examples/Example.NetCore.3.1.WithCredentialsValidator/Example.NetCore3.1.WithCredentialsValidator.csproj b/Examples/Core/NetCore3.1/Example.NetCore.3.1.WithCredentialsValidator/Example.NetCore3.1.WithCredentialsValidator.csproj similarity index 69% rename from Examples/Example.NetCore.3.1.WithCredentialsValidator/Example.NetCore3.1.WithCredentialsValidator.csproj rename to Examples/Core/NetCore3.1/Example.NetCore.3.1.WithCredentialsValidator/Example.NetCore3.1.WithCredentialsValidator.csproj index b72dbaf..0b08dc0 100644 --- a/Examples/Example.NetCore.3.1.WithCredentialsValidator/Example.NetCore3.1.WithCredentialsValidator.csproj +++ b/Examples/Core/NetCore3.1/Example.NetCore.3.1.WithCredentialsValidator/Example.NetCore3.1.WithCredentialsValidator.csproj @@ -6,7 +6,7 @@ - + diff --git a/Examples/Example.NetCore.3.1.WithCredentialsValidator/Program.cs b/Examples/Core/NetCore3.1/Example.NetCore.3.1.WithCredentialsValidator/Program.cs similarity index 100% rename from Examples/Example.NetCore.3.1.WithCredentialsValidator/Program.cs rename to Examples/Core/NetCore3.1/Example.NetCore.3.1.WithCredentialsValidator/Program.cs diff --git a/Examples/Example.NetCore.3.1.WithCredentialsValidator/Properties/launchSettings.json b/Examples/Core/NetCore3.1/Example.NetCore.3.1.WithCredentialsValidator/Properties/launchSettings.json similarity index 100% rename from Examples/Example.NetCore.3.1.WithCredentialsValidator/Properties/launchSettings.json rename to Examples/Core/NetCore3.1/Example.NetCore.3.1.WithCredentialsValidator/Properties/launchSettings.json diff --git a/Examples/Example.NetCore.3.1.WithCredentialsValidator/Startup.cs b/Examples/Core/NetCore3.1/Example.NetCore.3.1.WithCredentialsValidator/Startup.cs similarity index 100% rename from Examples/Example.NetCore.3.1.WithCredentialsValidator/Startup.cs rename to Examples/Core/NetCore3.1/Example.NetCore.3.1.WithCredentialsValidator/Startup.cs diff --git a/Examples/Example.NetCore.3.1.WithCredentialsValidator/appsettings.json b/Examples/Core/NetCore3.1/Example.NetCore.3.1.WithCredentialsValidator/appsettings.json similarity index 100% rename from Examples/Example.NetCore.3.1.WithCredentialsValidator/appsettings.json rename to Examples/Core/NetCore3.1/Example.NetCore.3.1.WithCredentialsValidator/appsettings.json diff --git a/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Controllers/ExampleController.cs b/Examples/Core/NetCore3.1/Example.NetCore3.1.AuthenticationWithRefreshToken/Controllers/ExampleController.cs similarity index 100% rename from Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Controllers/ExampleController.cs rename to Examples/Core/NetCore3.1/Example.NetCore3.1.AuthenticationWithRefreshToken/Controllers/ExampleController.cs diff --git a/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Example.NetCore3.1.AuthenticationWithRefreshToken.csproj b/Examples/Core/NetCore3.1/Example.NetCore3.1.AuthenticationWithRefreshToken/Example.NetCore3.1.AuthenticationWithRefreshToken.csproj similarity index 69% rename from Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Example.NetCore3.1.AuthenticationWithRefreshToken.csproj rename to Examples/Core/NetCore3.1/Example.NetCore3.1.AuthenticationWithRefreshToken/Example.NetCore3.1.AuthenticationWithRefreshToken.csproj index 9f29a51..030e1c5 100644 --- a/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Example.NetCore3.1.AuthenticationWithRefreshToken.csproj +++ b/Examples/Core/NetCore3.1/Example.NetCore3.1.AuthenticationWithRefreshToken/Example.NetCore3.1.AuthenticationWithRefreshToken.csproj @@ -6,7 +6,7 @@ - + diff --git a/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Program.cs b/Examples/Core/NetCore3.1/Example.NetCore3.1.AuthenticationWithRefreshToken/Program.cs similarity index 100% rename from Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Program.cs rename to Examples/Core/NetCore3.1/Example.NetCore3.1.AuthenticationWithRefreshToken/Program.cs diff --git a/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Properties/launchSettings.json b/Examples/Core/NetCore3.1/Example.NetCore3.1.AuthenticationWithRefreshToken/Properties/launchSettings.json similarity index 100% rename from Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Properties/launchSettings.json rename to Examples/Core/NetCore3.1/Example.NetCore3.1.AuthenticationWithRefreshToken/Properties/launchSettings.json diff --git a/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Startup.cs b/Examples/Core/NetCore3.1/Example.NetCore3.1.AuthenticationWithRefreshToken/Startup.cs similarity index 100% rename from Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/Startup.cs rename to Examples/Core/NetCore3.1/Example.NetCore3.1.AuthenticationWithRefreshToken/Startup.cs diff --git a/Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/appsettings.json b/Examples/Core/NetCore3.1/Example.NetCore3.1.AuthenticationWithRefreshToken/appsettings.json similarity index 100% rename from Examples/Example.NetCore3.1.AuthenticationWithRefreshToken/appsettings.json rename to Examples/Core/NetCore3.1/Example.NetCore3.1.AuthenticationWithRefreshToken/appsettings.json diff --git a/Examples/Example.NetCore3.1.BaseAuthentication/Controllers/ExampleController.cs b/Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Controllers/ExampleController.cs similarity index 100% rename from Examples/Example.NetCore3.1.BaseAuthentication/Controllers/ExampleController.cs rename to Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Controllers/ExampleController.cs diff --git a/Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Example.NetCore3.1.BaseAuthentication.csproj b/Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Example.NetCore3.1.BaseAuthentication.csproj new file mode 100644 index 0000000..25cae51 --- /dev/null +++ b/Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Example.NetCore3.1.BaseAuthentication.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + Example.NetCore3._1.BaseAuthentication + + + + + + + + diff --git a/Examples/Example.NetCore3.1.BaseAuthentication/Program.cs b/Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Program.cs similarity index 96% rename from Examples/Example.NetCore3.1.BaseAuthentication/Program.cs rename to Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Program.cs index 513feef..ed9f386 100644 --- a/Examples/Example.NetCore3.1.BaseAuthentication/Program.cs +++ b/Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Program.cs @@ -1,19 +1,19 @@ -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Hosting; - -namespace Example.NetCore3._1.BaseAuthentication -{ - public class Program - { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } - - public static IHostBuilder CreateHostBuilder(string[] args) - { - return Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); - } - } -} \ No newline at end of file +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; + +namespace Example.NetCore3._1.BaseAuthentication +{ + public class Program + { + public static void Main(string[] args) + { + CreateHostBuilder(args).Build().Run(); + } + + public static IHostBuilder CreateHostBuilder(string[] args) + { + return Host.CreateDefaultBuilder(args) + .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); + } + } +} diff --git a/Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Properties/launchSettings.json b/Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Properties/launchSettings.json new file mode 100644 index 0000000..d6b6957 --- /dev/null +++ b/Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Properties/launchSettings.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:31926", + "sslPort": 0 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "example", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "Example.NetCore3._1.BaseAuthentication": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "example", + "applicationUrl": "http://localhost:5000", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Startup.cs b/Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Startup.cs new file mode 100644 index 0000000..03fb858 --- /dev/null +++ b/Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/Startup.cs @@ -0,0 +1,43 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using TourmalineCore.AspNetCore.JwtAuthentication.Core; +using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; + +namespace Example.NetCore3._1.BaseAuthentication +{ + public class Startup + { + private readonly IConfiguration _configuration; + + public Startup(IConfiguration configuration) + { + _configuration = configuration; + } + + public void ConfigureServices(IServiceCollection services) + { + services.AddJwtAuthentication(_configuration.GetSection(nameof(AuthenticationOptions)).Get()); + + services.AddControllers(); + } + + public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + { + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseRouting(); + + app + .UseDefaultLoginMiddleware() + .UseJwtAuthentication(); + + app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); + } + } +} diff --git a/Examples/Example.NetCore3.1.PermissionBasedAuthentication/appsettings.json b/Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/appsettings.json similarity index 100% rename from Examples/Example.NetCore3.1.PermissionBasedAuthentication/appsettings.json rename to Examples/Core/NetCore3.1/Example.NetCore3.1.BaseAuthentication/appsettings.json diff --git a/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Controllers/ExampleController.cs b/Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/Controllers/ExampleController.cs similarity index 100% rename from Examples/Example.NetCore3.1.PermissionBasedAuthentication/Controllers/ExampleController.cs rename to Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/Controllers/ExampleController.cs diff --git a/Examples/Example.NetCore3.1.PermissionBasedAuthentication/CustomUserClaimsProvider.cs b/Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/CustomUserClaimsProvider.cs similarity index 100% rename from Examples/Example.NetCore3.1.PermissionBasedAuthentication/CustomUserClaimsProvider.cs rename to Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/CustomUserClaimsProvider.cs diff --git a/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Example.NetCore3.1.PermissionBasedAuthentication.csproj b/Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/Example.NetCore3.1.PermissionBasedAuthentication.csproj similarity index 69% rename from Examples/Example.NetCore3.1.PermissionBasedAuthentication/Example.NetCore3.1.PermissionBasedAuthentication.csproj rename to Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/Example.NetCore3.1.PermissionBasedAuthentication.csproj index b995f4c..a2c6685 100644 --- a/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Example.NetCore3.1.PermissionBasedAuthentication.csproj +++ b/Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/Example.NetCore3.1.PermissionBasedAuthentication.csproj @@ -6,7 +6,7 @@ - + diff --git a/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Program.cs b/Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/Program.cs similarity index 100% rename from Examples/Example.NetCore3.1.PermissionBasedAuthentication/Program.cs rename to Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/Program.cs diff --git a/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Properties/launchSettings.json b/Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/Properties/launchSettings.json similarity index 100% rename from Examples/Example.NetCore3.1.PermissionBasedAuthentication/Properties/launchSettings.json rename to Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/Properties/launchSettings.json diff --git a/Examples/Example.NetCore3.1.PermissionBasedAuthentication/Startup.cs b/Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/Startup.cs similarity index 100% rename from Examples/Example.NetCore3.1.PermissionBasedAuthentication/Startup.cs rename to Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/Startup.cs diff --git a/Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/appsettings.json b/Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/appsettings.json new file mode 100644 index 0000000..d09d8c4 --- /dev/null +++ b/Examples/Core/NetCore3.1/Example.NetCore3.1.PermissionBasedAuthentication/appsettings.json @@ -0,0 +1,6 @@ +{ + "AuthenticationOptions": { + "PublicSigningKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQAB", + "PrivateSigningKey": "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU" + } +} \ No newline at end of file diff --git a/Examples/Example.NetCore3.1.BaseAuthentication/Example.NetCore3.1.BaseAuthentication.csproj b/Examples/Example.NetCore3.1.BaseAuthentication/Example.NetCore3.1.BaseAuthentication.csproj deleted file mode 100644 index 3e2aab9..0000000 --- a/Examples/Example.NetCore3.1.BaseAuthentication/Example.NetCore3.1.BaseAuthentication.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - netcoreapp3.1 - Example.NetCore3._1.BaseAuthentication - - - - - - - - - PreserveNewest - true - PreserveNewest - - - - diff --git a/Examples/Example.NetCore3.1.BaseAuthentication/Properties/launchSettings.json b/Examples/Example.NetCore3.1.BaseAuthentication/Properties/launchSettings.json deleted file mode 100644 index 5d24be0..0000000 --- a/Examples/Example.NetCore3.1.BaseAuthentication/Properties/launchSettings.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:51478", - "sslPort": 44316 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "Example.NetCore3._1.BaseAuthentication": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "http://localhost:5000" - } - } -} \ No newline at end of file diff --git a/Examples/Example.NetCore3.1.BaseAuthentication/Startup.cs b/Examples/Example.NetCore3.1.BaseAuthentication/Startup.cs deleted file mode 100644 index a6404f4..0000000 --- a/Examples/Example.NetCore3.1.BaseAuthentication/Startup.cs +++ /dev/null @@ -1,97 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System; -using System.Threading.Tasks; -using TourmalineCore.AspNetCore.JwtAuthentication.Core; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Middlewares.Login.Models; -using TourmalineCore.AspNetCore.JwtAuthentication.Core.Options; - -namespace Example.NetCore3._1.BaseAuthentication -{ - public class Startup - { - private readonly IConfiguration _configuration; - - public Startup(IConfiguration configuration) - { - _configuration = configuration; - } - - public void ConfigureServices(IServiceCollection services) - { - services.AddJwtAuthentication(_configuration.GetSection(nameof(AuthenticationOptions)).Get()); - - services.AddControllers(); - } - - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - - app.UseRouting(); - - //app - // .OnLoginExecuting(OnLoginExecuting) - // .OnLoginExecuted(OnLoginExecuted) - // .UseDefaultLoginMiddleware() - // .UseJwtAuthentication(); - - //app - // .UseDefaultLoginMiddleware() - // .OnLoginExecuting(OnLoginExecuting) - // .OnLoginExecuted(OnLoginExecuted) - // .UseJwtAuthentication(); - - //app - // .OnLoginExecuting(OnLoginExecuting) - // .UseDefaultLoginMiddleware() - // .OnLoginExecuted(OnLoginExecuted) - // .UseJwtAuthentication(); - - //app - // .OnLoginExecuting(OnLoginExecuting) - // .OnLoginExecuted(OnLoginExecuted) - // .UseDefaultLoginMiddleware() - // .UseJwtAuthentication(); - - //app - // .OnLoginExecuted(OnLoginExecuted) - // .UseDefaultLoginMiddleware() - // .UseJwtAuthentication(); - - //app - // .OnLoginExecuting(OnLoginExecuting) - // .OnLoginExecuted(OnLoginExecuted); - - //app - // .UseDefaultLoginMiddleware() - // .UseJwtAuthentication(); - - app.UseCookieLoginMiddleware(new CookieAuthOptions - { - Key = "ExampleCookieName", - }); - - app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); - } - - private Task OnLoginExecuting(LoginModel data) - { - Console.WriteLine($"OnLoginExecuting: {data.Login}"); - return Task.CompletedTask; - } - - private Task OnLoginExecuted(LoginModel data) - { - Console.WriteLine($"OnLoginExecuted: {data.Login}"); - return Task.CompletedTask; - } - } -} \ No newline at end of file diff --git a/Examples/Example.NetCore3.1.BaseAuthentication/appsettings.json b/Examples/Example.NetCore3.1.BaseAuthentication/appsettings.json deleted file mode 100644 index dc634db..0000000 --- a/Examples/Example.NetCore3.1.BaseAuthentication/appsettings.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "AuthenticationOptions": { - "PublicSigningKey": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQAB", - "PrivateSigningKey": "MIIEowIBAAKCAQEAsDwLnM5sbVi326YDsLvMkQLXDKVAaHrJZ/MwkoxF4Hmq4+pu4KojgQyVDtjseXG8UW5wbxW58eXG8V0XgJzsD8zQX2Z1bBawpIeD9sXf/5CFZGif85YFIqS3brqR3ScdGxYHXcwrUMGUCThxe918Q0aNXzdSxGGP2v7ZbtpFhLRyrTXHl4u6k3eyYG7zCkwextnMb9CJuCR7x1ua1V1S0xljAqg5PicFjt0vVSKzPM/Djw7XK84sJXxaet7t4cNtXVJIAyXUMsSli6gg9Cw9CEUSE40iWUR/6wrdUYAchk3vWiBhMmnufwzmFRLKHOH9Fz8buJVSrRfyt7a6S2iN+wIDAQABAoIBAQCvue/KV3p+Pex2tD8RxvDf13kfPtfOVkDlyfQw7HXwsuDXijctBfmJAEbRGzQQlHw2pmyuF3fl4DxTB4Qb1lz8FDniJoQHV0ijhgzrz7rfVffsevajKH/OX3gYjShM4GeBTqHhwWefiqZV21YtMFhrrLniq4N4FeAfeebNRg/zlWEigraxqAWb4cplnxBE3qOBECKXdF/B8uhp743BU/2HLSO5BUdhtPlN3FKoYdyqtrKyNO2z7rC+Gk8tNd+KbMHDUMiOQXzbXkpsXYKAug9iTW+gxZG/bNyzGNrJBFrUYb1fP4iZphbxBJgobNYJBKA565cAX/wI5lFakTBB0YAhAoGBAOk0TyV0dA8WJ6NrWmRUBKsKvkSREhBveW+P3LtA8a1IgQf4K6ohIfcq9w/+nRvTLPIxo67FcqEyzVUu9TOafzIi59w4RBWG/HKOZ5lvIVicbuPyclPVWyC+9bMMgWEJy9wGwE+fGh3AvAA4PXNBcjOqfT0sSF9PBUo5qN11Q/qHAoGBAMF2IL+cXgPiUta4XoMh14ksJiwHtZeMkj+kauU3rctDITSkIGMFp4q0W5UUSG1yPcW/++rMQfuAjCZotdNpbQT+g+KfG44DMT5W7nRgv60S0/6X/OoLIhCue19yLMVzFpai0YEH+s24/XNnwl53K34G1zVMCsZcIuIng8SZVintAoGAJP/1pr2pRFOBin4X418pNnIH6h0SPqVRIRA0N0mAjru4LSmE1ANZvjuE43bEOovwz6Rskegl3cmPpnpC0SMsFypOmzQaKUg3eX16lm95XPPE7EmlNgPd534kwXm0dU72lzxC+t8FZ78SlP5XUZgKpIPiRvhlqymAb1xinHBkjrUCgYAB144YRPTgNJd1U+wSc5AJzlHOuYQRHVWHJZme9RjChrEaPzXPu44M1ArLMJY/9IaCC4HqimdWbbLn6rdQfAB9u66lyb4JbB5b6Zf7o7Avha5fDjNqRxDb981U61Fhz+a3KHW2NM0+iDRhlOtU2u2fFZGXAFJZ8Saj4JxwksUvQQKBgEQ1TAW/INhWSkEW8vGeLnjV+rxOx8EJ9ftVCRaQMlDEDlX0n7BZeQrQ1pBxwL0FSTrUQdD02MsWshrhe0agKsw2Yaxn8gYs1v9HMloS4Q3L2zl8pi7R3yx72RIcdnS4rqGXeO5t8dm305Yz2RHhqtkBmpFBssSEYCY/tUDmsQVU" - } -} \ No newline at end of file