【问题标题】:Validate jwt token from ASP.NET Core controller when not using Authorize attribute在不使用 Authorize 属性时验证来自 ASP.NET Core 控制器的 jwt 令牌
【发布时间】:2023-03-15 08:58:01
【问题描述】:

我的客户正在发送带有一些请求的 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 以便我可以获取它,或者是否有一种简单的方法可以验证令牌,但我不知道?

感谢任何帮助

【问题讨论】:

  • 为什么采用这种方法?从上下文中读取 sub 声明不是更容易吗?
  • 我不知道我可以做 [AllowAnonymous] 和 [Authorize]。如果它是授权用户,我只是在检查 IsAuthenticated 之后从身份中获取子项 :) 我看不到树木的福雷斯特。

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


【解决方案1】:

由于您的访问令牌是由 IdentityServer4 生成的,因此您应该使用 IS4 Introspection Endpoint 对其进行验证。这将为您提供关于它是否有效以及它是否仍然有效的明确答案。

有关 Introspection Endpoint 的信息位于 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

【讨论】:

  • 但是我已经有了 jwt 令牌和我拥有的 api,接收 jwt 令牌可以使用授权属性验证 jwt 令牌。没有办法让我使用所有已经存在的信息。使用授权属性时,Web api必须在某处执行此操作吗?我不认为调用身份服务器是一个可靠的解决方案,因为可能会有很多调用。
【解决方案2】:

在您的控制器中,您可以这样做:

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

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

【讨论】:

  • T.J.是对的。出于某种原因,我在想,如果您使用 AllowAnonymous 修饰操作,它不会填充 IsAuthenticated 属性,但确实如此。如果您只需要子,则可以访问声明。
  • 所以我可以仅仅因为请求中设置了 jwt 令牌就可以访问它们吗?我上班的时候试试这个!
  • 这不起作用。如果我通过请求发送令牌,则不会设置 IsAuthenticated 并且不会填充声明。我认为授权会填写此内容。
  • mslot 好消息是令牌仍然需要验证,具体取决于您配置身份验证的方式。您所说的表明该令牌尚未经过验证,您可以检查并确保您发送的是有效令牌..
【解决方案3】:

我想知道的是:有没有办法让我验证令牌?我知道 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 token 详情请参考this document

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

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

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

【讨论】:

  • 为我辩护,我从令牌中使用的数据严格用于标记数据库中的一些用户相关信息。它不适用于登录或其他重要的东西。如果坏人更改了 jwt 令牌,它不会暴露任何经过身份验证的内容。
  • @mslot ,则不需要使用身份服务器4,只需使用 jwt 令牌身份验证即可使用 SymmetricSecurityKey 颁发令牌。在 api 方面,设置相同的 SymmetricSecurityKey 并使用 AddJwtBearer 进行验证
  • 我将 identityserver4 用于所有其他端点,但对于这一端点,我授权和未授权都应该具有访问权限。但是当授权人调用它时,我想要提供的访问令牌中的用户 ID。我不知道该怎么做 AND 验证令牌。
  • 我突然想到你可以拥有 [AllowAnonymous] 和 [Authorize]。然后我可以检查 IsAuthorized,并获取用户 ID。这将验证令牌(如果存在)。
  • 首先,设置动作allowanonymous,并编写一个中间件以在http上下文中从请求中获取令牌,验证和解码令牌,获取您的声明,如图here
猜你喜欢
  • 2017-08-11
  • 2019-06-22
  • 2020-08-22
  • 2017-03-31
  • 2020-09-04
  • 2020-07-01
  • 2017-10-26
  • 2021-11-24
  • 1970-01-01
相关资源
最近更新 更多