基于多租户Asp.net Core网站中参数的JWT身份验证

问题描述:

我正在.net core 2.1网站中使用基于JWT的身份验证.目前,这可以正常工作.现在,我必须使一个API多租户,每个租户将拥有它自己的密钥.租户ID将作为参数传递给API.

I am using JWT based authentication in my .net core 2.1 web site. Currently this works fine. Now, I have to make one API multi-tenant and each tenant will have it's own secret key. The tenant Id will be passed as parameter to the API.

        [Authorize]
        [HttpGet("tenant/{id}")]
        public async Task<IActionResult> GetInfo(string id)
        {
        }

每个租户都将签署JWT,并将其添加到Authorization标头中.我无法考虑一种基于参数更改IssuerSigningKey的方法.我尝试了以下操作:

Each tenant will sign the JWT and will add to Authorization header. I am not able to think of a way to change IssuerSigningKey based on the parameter. I tried following:

  1. 通过使其成为[AllowAonymus]来验证API中的JWT.这行得通,但我最终编写了所有的JWT验证代码.

  1. Validating the JWT inside the API by making it [AllowAonymus]. This works but I have end up writing all the JWT validating code.

实施ISecurityTokenValidator

我可以实现ISecurityTokenValidator来验证令牌,并在启动配置中使用它,如下所示:

I can implement ISecurityTokenValidator to validate the token and using this in startup configuration something like this:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
            {
                options.SecurityTokenValidators.Clear();
                options.SecurityTokenValidators.Add(new JWTSecurityTokenValidator());
            });

并实现了我自己的类来验证令牌.

And implemented my own class to validate the token.

public class JWTSecurityTokenValidator : ISecurityTokenValidator
{
    public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
    {
            // Implement the logic
    }
}

但是我最终还是举起了沉重的负担.另外,我无法访问ValidateToken中的参数"tenantId".

But again I end up doing heavy lifting. Also, I am not able to access the parameter "tenantId" in the ValidateToken.

3.使用IssuerSigningKeyResolver: 我可以实现一个委托:

3.Using IssuerSigningKeyResolver: I can implement a delegate:

IEnumerable<SecurityKey> IssuerSigningKeyResolver(string token, SecurityToken securityToken, string kid, TokenValidationParameters validationParameters)

同样,我无权访问"tenantId"参数来选择适当的密钥.

Again I don't's have access to the "tenantId" parameter to choose the appropriate key.

是否存在基于参数选择IssuerSigningKey的优雅解决方案,因此我无需编写自己的逻辑即可验证JWT?还是唯一的选择就是第一个选择?

Is there elegant solution to choosing IssuerSigningKey based on the parameter so that I don't need to write my own logic to validate JWT? Or only option is to go with first option?

您可以使用DI将IHttpContextAccessor实例传递到您的JWTSecurityTokenValidator中,并获取IHttpContextAccessor.HttpContext属性的值.

You can use DI to pass IHttpContextAccessor instance into your JWTSecurityTokenValidator and get value of IHttpContextAccessor.HttpContext property.

在.Net Core 2.1中,您可以使用扩展名注册:

From .Net Core 2.1 , you can register using extension :

services.AddHttpContextAccessor();

然后在您的自定义JWTSecurityTokenValidator中,进行修改以注入IHttpContextAccessor:

Then in your custom JWTSecurityTokenValidator , modify to inject the IHttpContextAccessor :

private readonly IHttpContextAccessor _httpContextAccessor;

public JWTSecurityTokenValidator(IHttpContextAccessor httpContextAccessor) {
    _httpContextAccessor = httpContextAccessor;
}

修改Startup.cs中的注册:

options.SecurityTokenValidators.Clear();

options.SecurityTokenValidators.Add(new JWTSecurityTokenValidator(services.BuildServiceProvider().GetService<IHttpContextAccessor>()));

因此,在ValidateToken方法中,您可以根据传递参数的方式从_httpContextAccessor.HttpContext中读取参数,从查询字符串或路径中读取该参数:

So that in ValidateToken method ,you can read the parameter from _httpContextAccessor.HttpContext , according to how you pass the parameter , read it from query string or path :

public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
{
        var xx = _httpContextAccessor.HttpContext.Request;
        ........
}