AspNetCoreRateLimit
AspNetCoreRateLimit copied to clipboard
[Question] How does one limit via a berrer token method
I have a web api that authenticates using berrer token is their an example how to limit the user thottle via that method
You can do something like this:
using AspNetCoreRateLimit;
using Example.Core.Extensions;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
namespace Example.HttpRateLimiter
{
public class CustomClientHeaderResolveContributor : IClientResolveContributor
{
public const string JWT_KEY = "Jwt:Key";
public CustomClientHeaderResolveContributor()
{
}
private static ClaimsPrincipal GetPrincipalFromExpiredToken(string token, IConfiguration configuration)
{
var tokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
ValidateIssuer = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration[JWT_KEY])),
ValidateLifetime = true
};
var tokenHandler = new JwtSecurityTokenHandler();
var principal = tokenHandler.ValidateToken(token, tokenValidationParameters, out SecurityToken securityToken);
if (securityToken is not JwtSecurityToken jwtSecurityToken || !jwtSecurityToken.Header.Alg.Equals(SecurityAlgorithms.HmacSha256, StringComparison.InvariantCultureIgnoreCase))
throw new SecurityTokenException("Invalid token");
return principal;
}
private static string ResolveClient(HttpContext httpContext)
{
var configuration = httpContext.RequestServices.GetService(typeof(IConfiguration)) as IConfiguration;
if(httpContext.Request.Headers.TryGetValue("Authorization", out var authValue))
{
var strAuthValue = authValue.ToString();
if(strAuthValue.StartsWith("Bearer "))
{
var token = strAuthValue["Bearer ".Length..];
var user = GetPrincipalFromExpiredToken(token, configuration);
var userId = user.GetUserId<string>();
return userId;
}
}
var ip = httpContext.Connection.RemoteIpAddress?.ToString();
return ip;
}
public Task<string> ResolveClientAsync(HttpContext httpContext)
{
return Task.FromResult<string>(ResolveClient(httpContext));
}
}
}
I have my own extension for GetUserId.
@XzaR90
please,how to make your class CustomClientHeaderResolveContributor be used in asp.net core( code in startup.cs).^V^
I had to download the repo because the NuGet version is little outdated.
I made a fork and use it as a git submodule in my project.
I come back in 1 hour or so to post the startup part.
public static class ServiceCollectionRateLimiterExtension
{
public static void AddHttpRateLimiter(this IServiceCollection services, IConfiguration configuration)
{
//load general configuration from appsettings.json
services.Configure<ClientRateLimitOptions>(configuration.GetSection("ClientRateLimiting"));
//load client rules from appsettings.json
services.Configure<ClientRateLimitPolicies>(configuration.GetSection("ClientRateLimitPolicies"));
// inject counter and rules stores
services.AddSingleton<IClientPolicyStore, DistributedCacheClientPolicyStore>();
services.AddSingleton<IRateLimitCounterStore, DistributedCacheRateLimitCounterStore>();
// configuration (resolvers, counter key builders)
services.AddSingleton<IRateLimitConfiguration, CustomRateLimitConfiguration>();
}
}
@XzaR90, please could you provide an example of how to implement CustomRateLimitConfiguration : IRateLimitConfiguration?
@OutstandingBillNeal I am using the latest version of the nuget package now.
public class CustomRateLimitConfiguration : RateLimitConfiguration
{
public CustomRateLimitConfiguration(IOptions<IpRateLimitOptions> ipOptions, IOptions<ClientRateLimitOptions> clientOptions) : base(ipOptions, clientOptions)
{
}
public override void RegisterResolvers()
{
ClientResolvers.Add(new CustomClientHeaderResolveContributor());
}
}
public static void AddHttpRateLimiter(this IServiceCollection services, IConfiguration configuration)
{
// load general configuration from appsettings.json
services.Configure<ClientRateLimitOptions>(opt => configuration.GetSection("ClientRateLimiting").Bind(opt));
// load client rules from appsettings.json
services.Configure<ClientRateLimitPolicies>(opt => configuration.GetSection("ClientRateLimitPolicies").Bind(opt));
services.AddDistributedRateLimiting<AsyncKeyLockProcessingStrategy>();
// configuration (resolvers, counter key builders)
services.AddSingleton<IRateLimitConfiguration, CustomRateLimitConfiguration>();
}
public static class ClaimsPrincipalExtension
{
public static T GetUserId<T>(this ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException(nameof(principal));
}
var nameIdentifier = principal.FindFirstValue(ClaimTypes.NameIdentifier);
if (typeof(T) == typeof(Guid))
{
if (Guid.TryParse(nameIdentifier, out Guid result))
{
return (T)(object)result;
}
return default;
}
return nameIdentifier != null ? (T)Convert.ChangeType(nameIdentifier, typeof(T)) : default;
}
public static string GetUserName(this ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException(nameof(principal));
}
return principal.FindFirstValue(ClaimTypes.Name);
}
public static string GetUserEmail(this ClaimsPrincipal principal)
{
if (principal == null)
{
throw new ArgumentNullException(nameof(principal));
}
return principal.FindFirstValue(ClaimTypes.Email);
}
}
I hope it helps!