在 jwt 令牌验证失败后继续授权

Posted

技术标签:

【中文标题】在 jwt 令牌验证失败后继续授权【英文标题】:Authorization is continuing after a jwt token has failed validation 【发布时间】:2021-12-08 04:45:46 【问题描述】:

我已经使用以下代码实现了一个支持 jwt 令牌授权的 api:

services.AddAuthentication(bearerScheme)
    .AddJwtBearer(bearerScheme, config =>
    
        config.Authority = authority;
        config.Audience = resourceId;

我还实现了一个自定义属性,它提供了进一步的基于权限的验证,以及它自己的 AuthorizationPolicyProvider 和 AuthorizationHandler。 发送有效令牌没有问题。默认的 JwtSecurityTokenHandler 在我的客户处理程序触发之前触发并验证令牌并使用令牌来验证用户权限。 然而,发送过期的令牌并没有像我预期的那样工作。 似乎发生的事情是 JwtSecurityTokenHandler 触发并拒绝令牌并出现以下错误 - 正如预期的那样

IDX10223: Lifetime validation failed. The token is expired.

我不明白为什么我的 AuthorizationHandler 然后被触发,然后使用无效的访问令牌联系另一个 api 并因为令牌无效而失败。 理想情况下,我想:

    停止 jwt 验证并返回 401 错误,因为令牌失败,或者 不知何故能够在我的处理程序中获得 jwt 验证的结果并自己抛出错误

有人知道我该怎么做吗? 我很想了解为什么在身份验证失败时还要处理控制器方法上的属性,因为在身份验证失败后继续对我来说似乎很奇怪?

【问题讨论】:

您如何将您的身份验证方案与您的授权方案挂钩,或者您是否将此身份验证方案设置为默认身份验证方案? 我已将身份验证方案设置为默认值,即services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)。我没有具体的授权方案。我刚刚创建了一个继承自 DefaultAuthorizationPolicyProvider 的客户策略提供程序,并已将其注册到 DI,如下所示:services.AddSingleton<IAuthorizationPolicyProvider, SecurePolicyProvider>(); 【参考方案1】:

简答

很可能,.AddJwtBearer() 上的配置以某种方式将 (JwtBearerOptions).TokenValidationParameters.ValidateLifetime 上的最终设置设置为 false

另一种可能是服务器上的系统时钟有问题(这种情况很少发生)。

要使其在Authentication 步骤失败,请尝试任一方法

.AddJwtBearer(options =>
    
        //... Some other config
        options.TokenValidationParameters.ValidateLifetime = true;
        //... In case options.TokenValidationParameters.ValidateLifetime still got override somehow, do this
        options.TokenValidationParameters.LifetimeValidator = (nbf, exp, _, _) => nbf < DateTime.UtcNow && exp > DateTime.UtcNow;
    
)

幕后

我们必须从AuthenticationMiddleware 开始。 Schemes.GetRequestHandlerSchemesAsync() 不会收回任何东西进行迭代(如果有一些好奇,请在 IAuthenticationRequestHandlerIAuthenticationHandler 进一步调查)。

var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync(); 将返回我们都知道的默认身份验证方案。然后它调用context.AuthenticateAsync(),这是一个扩展here,利用AuthenticationService。现在AuthenticationHandler 将作为经典。它只会将 jwt 令牌转换为 ClaimPrincipal 对象。如果它在这个过程步骤中没有快速失败,它将流向AuthorizationMiddleware,这肯定会评估我们的策略(又名,AuthorizationHandler 代码块无论如何都会被触发)。

所以,我们现在要做的就是让从 jwt 到 ClaimPrincipal 对象的转换过程失败。这样,AuthorizationHandler 就不会触发,这可以在 Short answer 部分完成。

【讨论】:

【参考方案2】:

在 ASP.NET Core 中,成功的身份验证默认不是授权的要求,因为它们有不同的用途:

Authentication:恢复用户身份 Authorization:决定是否授予访问权限

在请求管道中(如果这是触发授权的地方),授权中间件会尝试使用授权策略(如果有)上给定的身份验证方案来恢复用户的身份。如果没有一个认证方案成功,认证结果就是 NO RESULT。在这种情况下,将针对未经身份验证的用户评估授权策略。

如果您要强制使用经过身份验证的用户,则需要在使用RequireAuthenticatedUser 构造策略时明确指定它:

new AuthorizationPolicyBuilder()
    .RequireAuthenticatedUser()
    .Build();

您还可以检查User.Identity.IsAuthenticated 以确定用户是否在您的授权处理代码中经过身份验证,并且仅在经过身份验证的场景中调用您的 API。

您还可以选择忽略未经身份验证的用户并让其他授权处理程序根据其他因素决定“匿名用户”是否应该有权访问资源,或者通过从您的代码返回失败的授权结果来大声失败。

如果您对源代码感兴趣,请查看PolicyEvaluator

【讨论】:

以上是关于在 jwt 令牌验证失败后继续授权的主要内容,如果未能解决你的问题,请参考以下文章

JWT 令牌身份验证失败并显示消息“PII 已隐藏”

验证时 JWT 令牌始终无效

使用 SignalR 的 JWT 身份验证失败

JWT/OAuth 令牌签名验证失败

在刷新身份验证令牌时处理多个未经授权的请求

构建 VSTS 扩展 azure webapp 身份验证 JWT 令牌验证失败