".AddOpenIdConnect()中间件澄清"

8
所以,我正在尝试使用ASP.NET Core 3.1实现OIDC客户端应用程序。我尝试利用 .AddOpenIdConnect() .AddJswtBearer() 中间件。然而,我需要一些澄清关于这个中间件在做什么方面的问题。
以下是我当前的中间件配置:
.AddOpenIdConnect(options =>
{
    options.Authority = Configuration["auth:oidc:authority"];
    options.ClientId = Configuration["auth:oidc:clientid"];
    options.ClientSecret = Configuration["auth:oidc:clientsecret"];
    options.ResponseType = OpenIdConnectResponseType.Code;
    options.GetClaimsFromUserInfoEndpoint = true;
    options.SaveTokens = true;
})
.AddJwtBearer(options =>
{
    options.Authority = Configuration["auth:oidc:authority"];
    options.Audience = Configuration["auth:oidc:clientid"];
    options.TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidIssuer = Configuration["auth:oidc:authority"],
        ValidAudience = Configuration["auth:oidc:clientid"],
        ValidateIssuerSigningKey = true,
        ClockSkew = TimeSpan.Zero
     };
}

我注意到应用程序在首次启动时会请求授权服务器的/.well-known/oidc-configuration/.well-known/keys端点,如下所示的我的Fiddler捕获

Fiddler capture of config and keys endpoint

它在哪里执行?

我也尝试验证从授权服务器接收到的JWT是否有效(即在服务器发送它和客户端接收它之间没有被篡改)。当我在.AddJwtBearer()中添加TokenValidationParameters对象时,我认为会发生这种情况。为了测试这个,我尝试更改TokenValidationParameters中的Valid Audience为像asdkwewrj这样的内容,但我知道这不是我的令牌的有效受众。但是,我从未收到来自客户端的错误,说受众无效。认证仍然有效,我能够访问我的安全仪表板。

我还想实现refresh_token grant_type与此OIDC客户端。我认为.AddOpenIdConnect()中的options.saveTokens将允许我保存令牌。看起来它们被保存为cookie,但这些cookie看起来与我的令牌值完全不同(我的访问令牌是JWT,但在我看到的cookie中,没有一个以ey开头)。

简而言之,我正在努力理解以下内容:

  1. 如果我已经定义了正确的JwtBearerOptions(如上所示),那么这个.AddJwtBearer()中间件是否会为我验证ID Token?还是说我需要手动根据JWKs URI验证ID token?
  2. 如果我必须手动使用来自JWKs URI的JWKs验证ID token,那么当中间件请求/.well-known/keys端点时,我应该如何存储这些JWKs?
  3. 如何获取与访问令牌和刷新令牌对应的cookie,然后将刷新令牌发送到我的授权服务器?
  4. 我注意到我可以在这两个中间件中都使用options.Events。其中任何一个可以解决我尝试完成的任何任务吗?
  5. 总体而言,这两个中间件为我处理了什么,我不应该手动进行(例如令牌验证和/或令牌更新)?

谢谢! 我对像这样深入地开发ASP.NET还比较新,所以我感谢任何回答。

2个回答

14
首先,OIDC身份验证方案和JWT承载者身份验证方案彼此独立。OIDC主要用于服务器端身份验证,并且基本上永远不会单独使用,而是始终与Cookie方案一起使用。原因是OIDC方案仅用于身份验证,但无法自行持久化信息。我在我的另一个答案中更详细地解释了OIDC的身份验证流程。
至于JWT承载者,这种身份验证方案将在每个请求上运行,因为它完全是无状态的,并且期望客户端始终使用Authorization头进行身份验证。这使其主要用于保护API,因为浏览器无法为正常的浏览器请求提供JWT。
因此,您应首先问自己是否正在保护您的服务器端Web应用程序(例如使用Razor视图或Razor页面),在这种情况下,您需要使用OIDC和Cookie身份验证方案,或者如果您正在保护您的API,则需要使用JWT。当然,答案可能是“两者都是”,在这种情况下,您需要使用这三种方案,但是ASP.NET Core不会在没有进一步配置的情况下支持这一点。
搞清楚了这一点,让我们来回答您的问题:
  • 请求 /.well-known/oidc-configuration/.well-known/keys 是由 OIDC 和 JWT 令牌方案共同完成的,目的是从您的身份提供者检索信息。它们将定期执行此操作以更新其数据,包括有关用于验证令牌的签名密钥的信息。这发生在方案处理程序中,通常对您不可见。

  • JWT 令牌方案正确设置后,将为您验证令牌。它将通过使用检索到的签名密钥来验证签名,然后可能会检查其他属性,例如指定的受众或其寿命。

  • 您永远不应该需要手动验证令牌。这是认证方案的工作。您正在使用身份验证堆栈,因此只需访问您的应用程序中的用户主体而无需执行任何操作。

  • 使用 数据保护 保护 cookie,以使其免受伪造。为了检索存储在 SaveTokens = true 中的令牌,您可以在 HTTP 上下文上使用 GetTokenAsync 方法。

  • 您可以使用身份验证事件来增加身份验证方案的默认行为。但是,如果要使用标准机制验证您的令牌,则不需要这样做。

  • 只有一个中间件:身份验证中间件。它使用配置的身份验证方案对用户进行身份验证,因此一旦正确设置,经过身份验证的用户就可以在整个应用程序中(例如在控制器、MVC过滤器、Razor视图等)使用。


  • 谢谢您提供的所有澄清信息,这对我很有帮助。但是,还有一些后续问题:
    1. 我不需要在客户端担心ID令牌验证,这意味着我不需要使用.AddJwtBearer()中间件吗?
    2. 是否有任何方法可以查看当请求/.well-known/keys端点时,中间件存储JWKs的位置?
    - deathcat05
    另一个后续问题:我想知道是否有一种方法可以查看JWKs,因为我注意到在.AddOpenIdConnect()中间件的TokenValidationParameters中,有一个选项可以设置ValidateIssuerSigningKey,还有一个选项可以设置IssuerSigningKey(s),但也有一个IssuerSigningKeyValidator。如果没有设置任何这些内容,中间件仍然可以正确验证JWK吗? - deathcat05
    1
    默认情况下,JwtBearerOptions.ConfigurationManager 用于从元数据终结点(.well-known/openid-configuration和签名密钥)请求配置。但是您也可以通过设置 JwtBearerOptions.Configuration 直接配置身份验证配置。 - poke
    1
    那个配置管理器也会存储密钥(和配置),直到它再次刷新(这经常发生)。您可以从选项中加载它,并调用其 GetConfigurationAsync 方法以访问元数据端点中的配置。通常,不需要这样做,因为身份验证方案会为您完成这项工作。 - poke
    好的,非常好。看起来最好的方法是让认证方案为我处理一切。 - deathcat05

    3
    这个 .AddJwtBearer() 中间件是否会自动验证 ID Token,如果我已经正确定义了 JwtBearerOptions(就像我在上面做的那样)?还是我需要手动使用 JWKs URI 验证 ID Token?
    AddJwtBearer 只用于API验证访问令牌并创建用户(ClaimsPrincipal)。它只能做这些。它不涉及 id token。
    通常,把API放在一个单独的服务中更容易理解谁在做什么。当你将客户端和API混在同一个服务中时,可能更难推理出结果。
    如果我必须使用 JWKs URI 手动验证 ID Token,当中间件请求 /.well-known/keys 端点时,我应该如何存储这些 JWKs?我如何获取与访问令牌和刷新令牌相对应的 Cookie,并将刷新令牌发送到我的授权服务器?
    ID Token 会由 AddOpenIdConnect 自动验证和处理。您无需自行验证 ID Token。AddOpenIdConnect 将创建 Cookie,并可选择将令牌存储在 Cookie 中。
    总的来说,这两个中间件为我处理了什么,使我不需要手动操作(例如令牌验证和/或令牌续订)?
    简而言之:
    对于客户端,请使用.AddOpenIdConnect(),允许用户登录。
    对于后端API,请使用.AddJwtBearer()。
    令牌续订是一个不同的问题,它们都没有默认处理。对于这个问题,您可以考虑使用IdentityModel.AspNetCore或自己实现一些方法。
    为了补充这个答案,我写了一篇博文,详细介绍了这个主题:在ASP.NET Core中调试OpenID Connect声明问题

    好的,太棒了。这开始有些有意义了。如果我想要使用.AddOpenIdConnect()中间件验证所有ID令牌参数,我仍然可以利用TokenValidationParameters吗?此外,在我的应用程序中哪里可以查看关于经过身份验证的用户的所有声明数据? - deathcat05
    1
    一旦用户通过身份验证,您就可以在框架中访问HttpContext.User或其中的许多User属性(例如,在控制器、Razor视图或Razor页面上)。 - poke
    TokenValidator 用于验证访问令牌和 ID 令牌。 - Tore Nestenius

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接