From 9ea2723205fc28287a2ef5b8241ef92b3a694401 Mon Sep 17 00:00:00 2001 From: eilyushenko Date: Mon, 25 Nov 2024 23:37:05 +0100 Subject: [PATCH] Rate Limiter First Part --- .../Controllers/TargetController.cs | 18 +++++--- .../Attributes/AppliedRuleAttribute.cs | 15 ++++++ .../ConfigureJwtBearerOptions.cs | 39 +++++++++++++++- .../ExeptionHandling/ExceptionHandler.cs | 2 - .../Infrastructure/Filters/RuleFilter.cs | 46 +++++++++++++++++++ RateLimiter.Api/Infrastructure/IocConfig.cs | 37 +++++++++------ .../Models/Request/CreateTokenRequestModel.cs | 2 +- RateLimiter.Api/RateLimiter.Api.csproj | 5 -- RateLimiter.Api/Startup.cs | 3 +- .../Services/IKeyGeneratorService.cs | 10 ++++ .../Services/IRuleFactory.cs | 9 ++++ .../Services/IRuleService.cs | 11 +++++ .../Services/ITokenService.cs | 5 +- .../Implementation/KeyGeneratorService.cs | 6 +-- .../RateLimiter/Factory/RuleFactory.cs | 17 +++++++ .../RateLimiter/Rules/EU/LastCallTimeRule.cs | 15 ++++++ .../Rules/USA/RequestPerTimeRule.cs | 15 ++++++ .../Services/Implementation/TokenService.cs | 18 ++++---- .../{RegionTokenType.cs => RegionType.cs} | 2 +- RateLimiter.Core/Domain/Enums/RuleType.cs | 8 ++++ .../Exceptions/UnauthorizedException.cs | 16 ------- RateLimiter.Core/Helpers/CustomClaimTypes.cs | 10 ++++ 22 files changed, 245 insertions(+), 64 deletions(-) create mode 100644 RateLimiter.Api/Infrastructure/Attributes/AppliedRuleAttribute.cs create mode 100644 RateLimiter.Api/Infrastructure/Filters/RuleFilter.cs create mode 100644 RateLimiter.BusinessLogic/Services/IKeyGeneratorService.cs create mode 100644 RateLimiter.BusinessLogic/Services/IRuleFactory.cs create mode 100644 RateLimiter.BusinessLogic/Services/IRuleService.cs rename RateLimiter.Core/Helpers/KeyGenerator.cs => RateLimiter.BusinessLogic/Services/Implementation/KeyGeneratorService.cs (68%) create mode 100644 RateLimiter.BusinessLogic/Services/Implementation/RateLimiter/Factory/RuleFactory.cs create mode 100644 RateLimiter.BusinessLogic/Services/Implementation/RateLimiter/Rules/EU/LastCallTimeRule.cs create mode 100644 RateLimiter.BusinessLogic/Services/Implementation/RateLimiter/Rules/USA/RequestPerTimeRule.cs rename RateLimiter.Core/Domain/Enums/{RegionTokenType.cs => RegionType.cs} (74%) create mode 100644 RateLimiter.Core/Domain/Enums/RuleType.cs delete mode 100644 RateLimiter.Core/Exceptions/UnauthorizedException.cs create mode 100644 RateLimiter.Core/Helpers/CustomClaimTypes.cs diff --git a/RateLimiter.Api/Controllers/TargetController.cs b/RateLimiter.Api/Controllers/TargetController.cs index c2cae20e..b7226dc5 100644 --- a/RateLimiter.Api/Controllers/TargetController.cs +++ b/RateLimiter.Api/Controllers/TargetController.cs @@ -1,20 +1,24 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using RateLimiter.Api.Infrastructure.Attributes; +using RateLimiter.Api.Infrastructure.Filters; +using RateLimiter.Core.Domain.Enums; namespace RateLimiter.Api.Controllers { [Authorize] [ApiController] [Route("api/target")] - public class TargetController : ControllerBase + public class TargetController { [HttpGet] - [Route("test-endpoint")] - public Task TestEndpoint() - { - var a = User.Claims.ToList(); + [Route("limited-info")] + [AppliedRule(RuleType.RequestPerTimeSpan, RuleType.TimeSpanPassedSinceLastCall)] + [ServiceFilter(typeof(RuleFilter))] + public Task GetLimitedInfo() => Task.CompletedTask; - return Task.FromResult("Ok"); - } + [HttpGet] + [Route("full-info")] + public Task GetFullInfo() => Task.CompletedTask; } } diff --git a/RateLimiter.Api/Infrastructure/Attributes/AppliedRuleAttribute.cs b/RateLimiter.Api/Infrastructure/Attributes/AppliedRuleAttribute.cs new file mode 100644 index 00000000..88eeb3fb --- /dev/null +++ b/RateLimiter.Api/Infrastructure/Attributes/AppliedRuleAttribute.cs @@ -0,0 +1,15 @@ +using RateLimiter.Core.Domain.Enums; + +namespace RateLimiter.Api.Infrastructure.Attributes +{ + [AttributeUsage(AttributeTargets.Method)] + public class AppliedRuleAttribute : Attribute + { + public RuleType[] RuleTypes { get; } + + public AppliedRuleAttribute(params RuleType[] ruleTypes) + { + RuleTypes = ruleTypes; + } + } +} diff --git a/RateLimiter.Api/Infrastructure/Authentication/ConfigureJwtBearerOptions.cs b/RateLimiter.Api/Infrastructure/Authentication/ConfigureJwtBearerOptions.cs index f3fe856d..11098daf 100644 --- a/RateLimiter.Api/Infrastructure/Authentication/ConfigureJwtBearerOptions.cs +++ b/RateLimiter.Api/Infrastructure/Authentication/ConfigureJwtBearerOptions.cs @@ -2,6 +2,8 @@ using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using RateLimiter.BusinessLogic.Services; +using RateLimiter.Core.Domain.Enums; +using RateLimiter.Core.Helpers; namespace RateLimiter.Api.Infrastructure.Authentication { @@ -31,9 +33,42 @@ public void Configure(JwtBearerOptions options) RequireExpirationTime = false, ValidIssuer = tokenService.TokenSettings.Issuer, ValidAudience = tokenService.TokenSettings.Audience, - IssuerSigningKey = tokenService.KeyGenerator.GetKey(), + IssuerSigningKey = tokenService.KeyGeneratorService.GetKey(), + }; + + options.Events = new JwtBearerEvents + { + OnTokenValidated = context => + { + var claimsPrincipal = context.Principal; + + var regionClaim = claimsPrincipal.FindFirst(nameof(CustomClaimTypes.Region)); + var uniqueIdentifierClaim = claimsPrincipal.FindFirst(nameof(CustomClaimTypes.UniqueIdentifier)); + + if (regionClaim == null || uniqueIdentifierClaim == null) + { + context.Fail($"Required custom claims have been missed."); + return Task.CompletedTask; + } + + var regionType = regionClaim.Value; + var uniqueIdentifier = uniqueIdentifierClaim.Value; + + if (string.IsNullOrEmpty(regionType) || string.IsNullOrEmpty(uniqueIdentifier)) + { + context.Fail("Custom claim values are invalid."); + return Task.CompletedTask; + } + + if (!Enum.TryParse(regionType, out RegionType type)) + { + context.Fail($"Invalid value of claim: {nameof(CustomClaimTypes.Region)}."); + } + + return Task.CompletedTask; + } }; } } } -} +} \ No newline at end of file diff --git a/RateLimiter.Api/Infrastructure/ExeptionHandling/ExceptionHandler.cs b/RateLimiter.Api/Infrastructure/ExeptionHandling/ExceptionHandler.cs index 8d996dd4..414a0d59 100644 --- a/RateLimiter.Api/Infrastructure/ExeptionHandling/ExceptionHandler.cs +++ b/RateLimiter.Api/Infrastructure/ExeptionHandling/ExceptionHandler.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Diagnostics; using RateLimiter.Api.Infrastructure.ExeptionHandling.Model; -using RateLimiter.Core.Exceptions; using System.Net; namespace RateLimiter.Api.Infrastructure.ExeptionHandling @@ -35,7 +34,6 @@ private static async Task HandleExceptionAsync(HttpResponse response, Exception? response.StatusCode = exception switch { ArgumentException => (int)HttpStatusCode.BadRequest, - UnauthorizedException => (int)HttpStatusCode.Unauthorized, _ => (int)HttpStatusCode.InternalServerError, }; diff --git a/RateLimiter.Api/Infrastructure/Filters/RuleFilter.cs b/RateLimiter.Api/Infrastructure/Filters/RuleFilter.cs new file mode 100644 index 00000000..ae9c90f9 --- /dev/null +++ b/RateLimiter.Api/Infrastructure/Filters/RuleFilter.cs @@ -0,0 +1,46 @@ +using Microsoft.AspNetCore.Mvc.Filters; +using RateLimiter.Api.Infrastructure.Attributes; +using RateLimiter.BusinessLogic.Services; +using RateLimiter.Core.Domain.Enums; +using RateLimiter.Core.Helpers; +using System.Security.Claims; + +namespace RateLimiter.Api.Infrastructure.Filters +{ + public class RuleFilter : IAsyncActionFilter + { + private readonly IRuleFactory _ruleFactory; + + public RuleFilter(IRuleFactory ruleFactory) + { + _ruleFactory = ruleFactory; + } + + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + var appliedRuleAttribute = context.ActionDescriptor.EndpointMetadata + .OfType() + .FirstOrDefault(); + + if (appliedRuleAttribute == null || !appliedRuleAttribute.RuleTypes.Any()) + { + throw new Exception($"{nameof(AppliedRuleAttribute)} and {nameof(RuleFilter)} have been applied incorecctly."); + } + + var ruleTypes = appliedRuleAttribute.RuleTypes.ToList(); + var (regionType, uniqueId) = GetClaimValues(context.HttpContext.User?.Claims); + + // TO DO + + await next(); + } + + private (RegionType regionType, string uniqueId) GetClaimValues(IEnumerable claims) + { + var region = claims.FirstOrDefault(c => c.Type == nameof(CustomClaimTypes.Region)).Value; + var identifierId = claims.FirstOrDefault(c => c.Type == nameof(CustomClaimTypes.UniqueIdentifier)).Value; + + return ((RegionType)Enum.Parse(typeof(RegionType), region), identifierId); + } + } +} diff --git a/RateLimiter.Api/Infrastructure/IocConfig.cs b/RateLimiter.Api/Infrastructure/IocConfig.cs index 9a4a4ba5..d017cc5a 100644 --- a/RateLimiter.Api/Infrastructure/IocConfig.cs +++ b/RateLimiter.Api/Infrastructure/IocConfig.cs @@ -1,35 +1,46 @@ -using Microsoft.Extensions.Configuration; +using RateLimiter.Api.Infrastructure.Filters; using RateLimiter.BusinessLogic.Services; using RateLimiter.BusinessLogic.Services.Implementation; -using RateLimiter.Core.Helpers; +using RateLimiter.BusinessLogic.Services.Implementation.RateLimiter.Factory; +using RateLimiter.BusinessLogic.Services.Implementation.RateLimiter.Rules.EU; +using RateLimiter.BusinessLogic.Services.Implementation.RateLimiter.Rules.USA; using RateLimiter.Core.Settings; namespace RateLimiter.Api.Infrastructure { public static class IocConfig { - public static void AddRateLimiterServices(this IServiceCollection services) + public static void AddFilters(this IServiceCollection services) { - AddBussinessLogicServices(services); - AddDataAccessLayerRepositories(services); + services.AddScoped(); } - private static void AddBussinessLogicServices(this IServiceCollection services) - { } - - private static void AddDataAccessLayerRepositories(this IServiceCollection services) - { } - public static void AddTokenConfigurationServices(this IServiceCollection services, IConfiguration configuration) { services.Configure(configuration.GetSection(nameof(TokenSettings))); - services.AddSingleton(provider => + services.AddSingleton(provider => { var secretKey = configuration.GetValue("GeneratorSecretKey"); - return new KeyGenerator(secretKey); + return new KeyGeneratorService(secretKey); }); services.AddScoped(); } + + public static void AddRateLimiterServices(this IServiceCollection services) + { + AddBussinessLogicServices(services); + AddDataAccessLayerRepositories(services); + } + + private static void AddBussinessLogicServices(this IServiceCollection services) + { + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + } + + private static void AddDataAccessLayerRepositories(this IServiceCollection services) + { } } } diff --git a/RateLimiter.Api/Models/Request/CreateTokenRequestModel.cs b/RateLimiter.Api/Models/Request/CreateTokenRequestModel.cs index e4647197..dfd9bfe4 100644 --- a/RateLimiter.Api/Models/Request/CreateTokenRequestModel.cs +++ b/RateLimiter.Api/Models/Request/CreateTokenRequestModel.cs @@ -4,6 +4,6 @@ namespace RateLimiter.Api.Models.Request { public class CreateTokenRequestModel { - public RegionTokenType Type { get; set; } + public RegionType Type { get; set; } } } diff --git a/RateLimiter.Api/RateLimiter.Api.csproj b/RateLimiter.Api/RateLimiter.Api.csproj index f0c5cf96..3a8bef38 100644 --- a/RateLimiter.Api/RateLimiter.Api.csproj +++ b/RateLimiter.Api/RateLimiter.Api.csproj @@ -2,7 +2,6 @@ net8.0 - enable enable true $(NoWarn);1591 @@ -17,8 +16,4 @@ - - - - diff --git a/RateLimiter.Api/Startup.cs b/RateLimiter.Api/Startup.cs index 54aed311..06b17e12 100644 --- a/RateLimiter.Api/Startup.cs +++ b/RateLimiter.Api/Startup.cs @@ -27,6 +27,7 @@ public void ConfigureServices(IServiceCollection services) services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(); services.AddJwtBearerConfiguration(); + services.AddFilters(); services.AddRateLimiterServices(); services.AddSwaggerServices(); } @@ -44,13 +45,13 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) } app.UseHttpsRedirection(); + app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseErrorHandler(); - app.UseEndpoints(endpoints => { endpoints.MapControllers(); diff --git a/RateLimiter.BusinessLogic/Services/IKeyGeneratorService.cs b/RateLimiter.BusinessLogic/Services/IKeyGeneratorService.cs new file mode 100644 index 00000000..1c1dbb22 --- /dev/null +++ b/RateLimiter.BusinessLogic/Services/IKeyGeneratorService.cs @@ -0,0 +1,10 @@ +using Microsoft.IdentityModel.Tokens; + +namespace RateLimiter.BusinessLogic.Services +{ + public interface IKeyGeneratorService + { + string SigningAlgorithm { get; } + SecurityKey GetKey(); + } +} diff --git a/RateLimiter.BusinessLogic/Services/IRuleFactory.cs b/RateLimiter.BusinessLogic/Services/IRuleFactory.cs new file mode 100644 index 00000000..40d3605c --- /dev/null +++ b/RateLimiter.BusinessLogic/Services/IRuleFactory.cs @@ -0,0 +1,9 @@ +using RateLimiter.Core.Domain.Enums; + +namespace RateLimiter.BusinessLogic.Services +{ + public interface IRuleFactory + { + IRuleService GetRule(RegionType regionType, RuleType ruleType); + } +} diff --git a/RateLimiter.BusinessLogic/Services/IRuleService.cs b/RateLimiter.BusinessLogic/Services/IRuleService.cs new file mode 100644 index 00000000..79d5c734 --- /dev/null +++ b/RateLimiter.BusinessLogic/Services/IRuleService.cs @@ -0,0 +1,11 @@ +using RateLimiter.Core.Domain.Enums; + +namespace RateLimiter.BusinessLogic.Services +{ + public interface IRuleService + { + public RegionType RegionType { get; } + public RuleType RuleType { get; } + Task ApplyRule(); + } +} \ No newline at end of file diff --git a/RateLimiter.BusinessLogic/Services/ITokenService.cs b/RateLimiter.BusinessLogic/Services/ITokenService.cs index 6d3b6359..e715c31d 100644 --- a/RateLimiter.BusinessLogic/Services/ITokenService.cs +++ b/RateLimiter.BusinessLogic/Services/ITokenService.cs @@ -1,13 +1,12 @@ using RateLimiter.Core.Domain.Enums; -using RateLimiter.Core.Helpers; using RateLimiter.Core.Settings; namespace RateLimiter.BusinessLogic.Services { public interface ITokenService { - KeyGenerator KeyGenerator { get; } + IKeyGeneratorService KeyGeneratorService { get; } TokenSettings TokenSettings { get; } - Task GenerateTokenAsync(RegionTokenType type); + Task GenerateTokenAsync(RegionType type); } } diff --git a/RateLimiter.Core/Helpers/KeyGenerator.cs b/RateLimiter.BusinessLogic/Services/Implementation/KeyGeneratorService.cs similarity index 68% rename from RateLimiter.Core/Helpers/KeyGenerator.cs rename to RateLimiter.BusinessLogic/Services/Implementation/KeyGeneratorService.cs index 2e50b71f..f2fcb124 100644 --- a/RateLimiter.Core/Helpers/KeyGenerator.cs +++ b/RateLimiter.BusinessLogic/Services/Implementation/KeyGeneratorService.cs @@ -1,14 +1,14 @@ using Microsoft.IdentityModel.Tokens; using System.Text; -namespace RateLimiter.Core.Helpers +namespace RateLimiter.BusinessLogic.Services.Implementation { - public class KeyGenerator + public class KeyGeneratorService : IKeyGeneratorService { private readonly SymmetricSecurityKey _secretKey; public string SigningAlgorithm => SecurityAlgorithms.HmacSha256; - public KeyGenerator(string key) + public KeyGeneratorService(string key) { var secretBytes = Encoding.UTF8.GetBytes(key); _secretKey = new SymmetricSecurityKey(secretBytes); diff --git a/RateLimiter.BusinessLogic/Services/Implementation/RateLimiter/Factory/RuleFactory.cs b/RateLimiter.BusinessLogic/Services/Implementation/RateLimiter/Factory/RuleFactory.cs new file mode 100644 index 00000000..abd5c761 --- /dev/null +++ b/RateLimiter.BusinessLogic/Services/Implementation/RateLimiter/Factory/RuleFactory.cs @@ -0,0 +1,17 @@ +using RateLimiter.Core.Domain.Enums; + +namespace RateLimiter.BusinessLogic.Services.Implementation.RateLimiter.Factory +{ + public class RuleFactory : IRuleFactory + { + private readonly IEnumerable _rules; + + public RuleFactory(IEnumerable rules) + { + _rules = rules; + } + + public IRuleService GetRule(RegionType regionType, RuleType ruleType) + => _rules.Single(x => x.RegionType == regionType && x.RuleType == ruleType); + } +} diff --git a/RateLimiter.BusinessLogic/Services/Implementation/RateLimiter/Rules/EU/LastCallTimeRule.cs b/RateLimiter.BusinessLogic/Services/Implementation/RateLimiter/Rules/EU/LastCallTimeRule.cs new file mode 100644 index 00000000..86738f2c --- /dev/null +++ b/RateLimiter.BusinessLogic/Services/Implementation/RateLimiter/Rules/EU/LastCallTimeRule.cs @@ -0,0 +1,15 @@ +using RateLimiter.Core.Domain.Enums; + +namespace RateLimiter.BusinessLogic.Services.Implementation.RateLimiter.Rules.EU +{ + public class LastCallTimeRule : IRuleService + { + public RegionType RegionType => RegionType.EU; + public RuleType RuleType => RuleType.TimeSpanPassedSinceLastCall; + + public Task ApplyRule() + { + throw new NotImplementedException(); + } + } +} diff --git a/RateLimiter.BusinessLogic/Services/Implementation/RateLimiter/Rules/USA/RequestPerTimeRule.cs b/RateLimiter.BusinessLogic/Services/Implementation/RateLimiter/Rules/USA/RequestPerTimeRule.cs new file mode 100644 index 00000000..9efbce4c --- /dev/null +++ b/RateLimiter.BusinessLogic/Services/Implementation/RateLimiter/Rules/USA/RequestPerTimeRule.cs @@ -0,0 +1,15 @@ +using RateLimiter.Core.Domain.Enums; + +namespace RateLimiter.BusinessLogic.Services.Implementation.RateLimiter.Rules.USA +{ + public class RequestPerTimeRule : IRuleService + { + public RegionType RegionType => RegionType.US; + public RuleType RuleType => RuleType.RequestPerTimeSpan; + + public Task ApplyRule() + { + throw new NotImplementedException(); + } + } +} diff --git a/RateLimiter.BusinessLogic/Services/Implementation/TokenService.cs b/RateLimiter.BusinessLogic/Services/Implementation/TokenService.cs index 06a8d1a0..7307d17c 100644 --- a/RateLimiter.BusinessLogic/Services/Implementation/TokenService.cs +++ b/RateLimiter.BusinessLogic/Services/Implementation/TokenService.cs @@ -10,27 +10,25 @@ namespace RateLimiter.BusinessLogic.Services.Implementation { public class TokenService : ITokenService { - private const string UniqueIndentifier = "UniqueIdentifierId"; - - private readonly KeyGenerator _keyGenerator; + private readonly IKeyGeneratorService _keyGenerator; private readonly TokenSettings _tokenSettings; public TokenService( - KeyGenerator keyGenerator, + IKeyGeneratorService keyGenerator, IOptions options) { _keyGenerator = keyGenerator; _tokenSettings = options.Value; } - public KeyGenerator KeyGenerator => _keyGenerator; public TokenSettings TokenSettings => _tokenSettings; + public IKeyGeneratorService KeyGeneratorService => _keyGenerator; - public Task GenerateTokenAsync(RegionTokenType type) + public Task GenerateTokenAsync(RegionType type) { - if (type == RegionTokenType.None) + if (type == RegionType.None) { - throw new ArgumentException($"{nameof(RegionTokenType)} should not be set up in {RegionTokenType.None}."); + throw new ArgumentException($"{nameof(RegionType)} should not be set up in {RegionType.None}."); } var token = new JwtSecurityToken( @@ -38,8 +36,8 @@ public Task GenerateTokenAsync(RegionTokenType type) audience: _tokenSettings.Audience, claims: new List { - new Claim(nameof(RegionTokenType), type.ToString()), - new Claim(nameof(UniqueIndentifier), Guid.NewGuid().ToString()) + new Claim(nameof(CustomClaimTypes.Region), type.ToString()), + new Claim(nameof(CustomClaimTypes.UniqueIdentifier), Guid.NewGuid().ToString()) }, signingCredentials: new SigningCredentials(_keyGenerator.GetKey(), _keyGenerator.SigningAlgorithm)); diff --git a/RateLimiter.Core/Domain/Enums/RegionTokenType.cs b/RateLimiter.Core/Domain/Enums/RegionType.cs similarity index 74% rename from RateLimiter.Core/Domain/Enums/RegionTokenType.cs rename to RateLimiter.Core/Domain/Enums/RegionType.cs index 23d73181..0be5c785 100644 --- a/RateLimiter.Core/Domain/Enums/RegionTokenType.cs +++ b/RateLimiter.Core/Domain/Enums/RegionType.cs @@ -1,6 +1,6 @@ namespace RateLimiter.Core.Domain.Enums { - public enum RegionTokenType + public enum RegionType { None = 0, US = 1, diff --git a/RateLimiter.Core/Domain/Enums/RuleType.cs b/RateLimiter.Core/Domain/Enums/RuleType.cs new file mode 100644 index 00000000..2636a37b --- /dev/null +++ b/RateLimiter.Core/Domain/Enums/RuleType.cs @@ -0,0 +1,8 @@ +namespace RateLimiter.Core.Domain.Enums +{ + public enum RuleType + { + RequestPerTimeSpan = 1, + TimeSpanPassedSinceLastCall = 2, + } +} diff --git a/RateLimiter.Core/Exceptions/UnauthorizedException.cs b/RateLimiter.Core/Exceptions/UnauthorizedException.cs deleted file mode 100644 index e3aeec98..00000000 --- a/RateLimiter.Core/Exceptions/UnauthorizedException.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace RateLimiter.Core.Exceptions -{ - public class UnauthorizedException : Exception - { - public UnauthorizedException() - { } - - public UnauthorizedException(string message) - : base(message) - { } - - public UnauthorizedException(string message, Exception inner) - : base(message, inner) - { } - } -} diff --git a/RateLimiter.Core/Helpers/CustomClaimTypes.cs b/RateLimiter.Core/Helpers/CustomClaimTypes.cs new file mode 100644 index 00000000..8244e350 --- /dev/null +++ b/RateLimiter.Core/Helpers/CustomClaimTypes.cs @@ -0,0 +1,10 @@ +using RateLimiter.Core.Domain.Enums; + +namespace RateLimiter.Core.Helpers +{ + public static class CustomClaimTypes + { + public const string UniqueIdentifier = "IdentifierId"; + public const string Region = nameof(RegionType); + } +}