不使用Authorize属性时从ASP.NET Core控制器验证jwt令牌

时间:2019-12-19 19:52:52

标签: asp.net-core jwt asp.net-identity identityserver4

我的客户端正在向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中,以便我可以获取它,或者有一种简单的方法可以验证我不知道的令牌?

感谢您的帮助

3 个答案:

答案 0 :(得分:1)

由于访问令牌是由IdentityServer4生成的,因此您应该使用IS4自省端点对其进行验证。这将为您提供有关其是否有效以及是否仍处于活动状态的明确答案。

有关自省端点的信息位于IS4文档中,位于: http://docs.identityserver.io/en/latest/endpoints/introspection.html

如在这些文档中所引用的那样,与端点进行交互的最简单方法可能是使用IdentityModel客户端库(通过NuGet添加软件包),该库将IntrospectTokenAsync()扩展方法添加到HttpClient并返回TokenIntrospectionResponse对象,该对象具有您需要的信息。

IdentityModel客户端自省端点文档: https://identitymodel.readthedocs.io/en/latest/client/introspection.html

答案 1 :(得分:1)

您可以在控制器内部执行以下操作:

if(HttpContext.User.Identity.IsAuthenticated)          
{              
    var claims = HttpContext.User.Claims;          
}

,您可以检查索赔中是否有任何感兴趣的信息。 身份验证的用户身份已通过验证,并且无论是否应用Authorize属性都可用。如果用户的cookie已过期等,将返回false。

答案 2 :(得分:1)

  

我想知道的是:我是否可以验证令牌?我知道JwtSecurityTokenHandler可以调用“ ValidateToken”,但是此方法需要一个签名密钥,而且我真的不知道如何获取它。我使用IdentityServer 4生成令牌。

在验证由Identity Server发行的JWT令牌时(使用密钥对来发行/验证令牌),特定于验证签名。 API /资源服务器将拉低(并可能缓存)位于OIDC端点 <script async src="https://www.googletagmanager.com/gtag/js?id=UA-xxxxxx-x"></script> <script> window.dataLayer = window.dataLayer || []; function gtag() { dataLayer.push(arguments); } gtag('js', new Date()); gtag('config', 'UA-xxxxxxxx-x', { 'custom_map': { 'dimension1': 'district_state', 'dimension2': 'district_name', 'dimension3': 'user_type', 'dimension4': 'district_school_name' } }); gtag('event', 'data', { 'district_state': $('#ctl00_hdnState').val(), 'district_name': $('#ctl00_hdnDistrict').val(), 'district_school_name':$('#ctl00_hdnProvider').val(), 'user_type': $('#ctl00_HdnRole').val() }); 上的身份提供者发现文档。本文档包含允许资源服务器验证令牌,从https://xxx/.well-known/openid-configuration读取可用密钥的材料。

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

您可以使用jwks_uri中间件或JwtBearerAuthentication中间件来帮助完成该过程。代码示例here供您参考。如果要手动验证JWT令牌。点击here以获得代码示例。

  

我唯一的问题是jwt令牌没有经过验证,因此我猜想一个“坏人”可能会与有效日期时间混合在一起,并继续延长令牌寿命。

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