首先请注意,您没有在此处使用 ASP.NET Core Identity。身份是在身份验证系统之上构建的用户管理堆栈。您似乎将 OpenID Connect 与 IdentityServer 一起用作提供者,因此您的 Web 应用程序只会使用 OIDC 信息,而不必管理自己的身份(尽管 IdentityServer 可能正在使用 ASP.NET Core Identity)。
身份验证堆栈在 ASP.NET Core 中的工作方式是您可以配置一组身份验证方案。其中一些方案旨在组合使用,例如 cookie 身份验证方案很少单独使用,但也有可以完全单独使用的方案(例如 JWT Bearer 身份验证)。
身份验证操作
在身份验证领域,您可以执行某些操作:
-
身份验证:身份验证基本上意味着使用给定信息并尝试使用该信息对用户进行身份验证。因此,这将尝试创建一个用户身份并使其可用于框架。
例如,cookie 身份验证方案使用 cookie 数据来恢复用户身份。或者,JWT Bearer 身份验证方案将使用作为请求中 Authorization 标头的一部分提供的令牌来创建用户身份。
-
挑战:当一个身份验证方案受到挑战时,该方案应提示用户进行身份验证。例如,这可能意味着用户被重定向到登录表单,或者将重定向到外部身份验证提供程序。
-
禁止:当一个身份验证方案被禁止时,该方案基本上只是用一些东西来响应,告诉用户他们可能不会做他们试图做的任何事情。这通常是 HTTP 403 错误,可能是重定向到某个错误页面。
-
登录:当一个身份验证方案正在登录时,该方案被告知获取现有用户(ClaimsPrincipal)并以某种方式保持该用户。例如,在 cookie 身份验证方案上登录用户基本上会创建一个包含该用户身份的 cookie。
-
退出:这与登录相反,基本上会告诉身份验证方案删除该持久性。退出 cookie 方案将有效地使 cookie 过期。
请注意,并非所有身份验证方案都可以执行所有选项。登录和注销通常是特殊操作。 cookie 身份验证方案是一个支持登录和注销的示例,但 OIDC 方案无法做到这一点,而是依赖不同的方案来登录和持久化身份。这就是为什么您通常也会看到 cookie 方案。
典型的身份验证流程
身份验证方案可以显式使用。当您使用authentication extension methods on the HttpContext 之一时,例如httpContext.AuthenticateAsync(),您始终可以明确指定要用于此操作的身份验证方案。
因此,例如,如果您想使用 cookie 身份验证方案 "Cookie" 登录,您可以简单地从您的代码中这样调用它:
var user = new ClaimsPrincipal(…);
await httpContext.SignInAsync(user, "Cookie");
但在实践中,像这样直接明确地调用身份验证并不是最常见的事情。相反,您通常会依赖框架为您进行身份验证。为此,框架需要知道哪个身份验证方案用于什么操作。
这就是AuthenticationOptions 的用途。您可以配置这些选项,以便您可以明确定义要用作每个身份验证操作的默认身份验证方案:
您通常不会配置所有这些属性。相反,该框架有一些默认的回退,因此您可以只配置这些属性的一个子集。逻辑是这样的:
- 验证:
DefaultAuthenticateScheme,或DefaultScheme
- 挑战:
DefaultChallengeScheme,或DefaultScheme
- 禁止:
DefaultForbidScheme,或DefaultChallengeScheme,或DefaultScheme
- 登录:
DefaultSignInScheme,或DefaultScheme
- 注销:
DefaultSignOutScheme,或DefaultScheme
如您所见,如果未配置特定操作的默认值,则每个身份验证操作都会退回到 DefaultScheme。因此,您通常会看到正在配置 DefaultScheme,然后为需要不同方案的那些配置特定操作。
您的示例很好地说明了这一点:使用 OIDC,您将需要一个登录方案,该方案可以保留外部身份验证提供程序提供的身份。所以你通常会看到 OIDC 和 cookie 认证方案:
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
});
对于用户来说,正常的交互是通过 cookie 认证方案:当他们访问 web 应用程序时,cookie 认证方案将尝试使用他们的 cookie 对他们进行认证。所以使用cookie认证方案作为所有操作的默认方案。
挑战身份验证时例外:在这种情况下,我们希望将用户重定向到 OIDC 提供商,以便他们可以在那里登录并返回身份。所以我们将默认的challenge方案设置为OIDC方案。
此外,我们还将 OIDC 方案与 cookie 方案相链接。当用户受到挑战并使用其外部身份验证提供程序登录时,他们将以其外部身份被发送回 Web 应用程序。但是,OIDC 方案无法持久化该身份,因此它使用一个不同的方案(cookie 方案)登录,然后它将代表 OIDC 方案持久化身份。因此 cookie 方案将为 OIDC 身份创建一个 cookie,并且在下一次请求时,cookie 方案(这是默认方案)将能够使用该 cookie 再次对用户进行身份验证。
所以大多数时候,您只需指定默认方案就可以了,然后根据您的身份验证设置可能会更改一两个显式操作。但从理论上讲,您完全可以设置一个非常复杂的不同默认值和多种方案的设置:该框架在这里为您提供了很大的灵活性。