首页 > 解决方案 > 在不使用 Authorize 属性时验证来自 ASP.NET Core 控制器的 jwt 令牌

问题描述

我的客户正在发送带有一些请求的 jwt 令牌。几乎所有请求都在使用 [Authorize] 属性的 Web api 控制器。有了这个,我确信我的 jwt 令牌得到了正确验证,但对于某些端点来说,真的只是想获取 JWT 令牌并获取子值。我通过使用这个扩展方法来做到这一点:

public static class HttpContextAccessorExtensions
{
    public static string GetUserIdFromToken(this IHttpContextAccessor httpContextAccessor)
    {
        if (httpContextAccessor == null)
        {
            throw new ArgumentNullException(nameof(httpContextAccessor));
        }

        var context = httpContextAccessor.HttpContext;

        string userId = null;
        if (httpContextAccessor != null)
        {
            if (context != null)
            {
                var request = context.Request;
                if (request != null)
                {
                    request.Headers.TryGetValue("Authorization", out var bearer);

                    if (bearer.Any())
                    {
                        string t = bearer[0].Split(" ")[1];
                        var handler = new JwtSecurityTokenHandler();
                        var token = handler.ReadToken(t) as JwtSecurityToken;

                        var utcNow = DateTime.UtcNow;

                        if (utcNow >= token.ValidFrom &&
                            utcNow <= token.ValidTo)
                        {
                            userId = token.Claims.FirstOrDefault(_ => _.Type.Equals("sub")).Value;
                        }
                        else
                        {
                            userId = String.Empty;
                        }
                    }
                }
            }
        }

        return userId;
    }
}

我唯一的问题是 jwt 令牌没有经过验证,所以我猜一个“坏人”可能只是与有效的日期时间混在一起,并继续延长令牌的生命周期。如果我对此有误,请纠正我。

我想知道的是:有没有办法让我验证令牌?我知道 JwtSecurityTokenHandler 可以调用“ValidateToken”,但是这个方法需要一个签名密钥,我真的不知道如何得到这个。我使用 IdentityServer 4 来生成令牌。是否有一些简单的方法可以将密钥注入到 IoC 中以便我可以得到它,或者是否有一种简单的方法来验证令牌,我不知道?

任何帮助表示赞赏

标签: asp.net-corejwtasp.net-identityidentityserver4

解决方案


我想知道的是:有没有办法让我验证令牌?我知道 JwtSecurityTokenHandler 可以调用“ValidateToken”,但是这个方法需要一个签名密钥,我真的不知道如何得到这个。我使用 IdentityServer 4 来生成令牌。

验证 Identity Server 颁发的 JWT 令牌时(使用密钥对来颁发/验证令牌),专门用于验证签名。API/资源服务器将下拉(并可能缓存)位于 OIDC 端点的身份提供者发现文档:https://xxx/.well-known/openid-configuration。本文档包含允许资源服务器验证令牌、从中读取可用密钥的材料jwks_uri

使用密钥对意味着由 IDS4 使用私钥签名的 JWT 令牌。JWT 令牌是未加密的数字签名 JSON 有效负载,其中包含不同的属性(声明)以识别用户/角色。签名是 JWT 的最后一部分,需要用于验证有效负载。此签名是使用标头中描述的算法(例如 RS256)生成的,以防止未经授权的访问。在您的 api 中,您可以使用 IDS4() 发布的公钥jwks_uri来验证 JWT 令牌的签名。有关 JWT 令牌的更多详细信息,请参阅此文档

您可以使用JwtBearerAuthentication中间件或IdentityServer.AccessTokenValidation中间件来帮助完成该过程。这里的代码示例供您参考。如果要手动验证 JWT 令牌。单击此处获取代码示例。

我唯一的问题是 jwt 令牌没有经过验证,所以我猜测“坏人”可能只是与有效的日期时间混在一起,并继续延长令牌的生命周期。

不建议在不验证的情况下使用令牌。由于 JWT 令牌的签名部分是加密/编码使用(header+payload),即使有人更改了声明(过期时间),它也不会通过验证,因为他不知道 Identity Server 的私钥来发出正确的签名.


推荐阅读