.Net Core 2 OpenID Connect 身份验证和多重身份
.Net Core 2 OpenID Connect Authentication and multiple Identities
我仍在学习身份框架,并且在我的 .Net Core 2 MVC 应用程序中尝试设置身份验证时非常迷茫。感谢任何建议,因为我什至不确定我在做什么是正确的。
我需要为 身份验证 集成一个 OpenID Connect 身份提供者,并为 授权 使用辅助数据源。不方便的是,除了名称声明外,我不能使用 OIDC IdP 的任何声明。其余用户声明必须来自辅助数据源(通过自定义 UserStore
和 User
实体连接到身份框架)。
我正在使用 OpenId Connect provider 来处理身份验证。这工作正常并给了我第一个身份(我只能使用一个声明)。当我需要获取用户的第二个身份、将其添加到主体并将其设置为默认值 Identity
时,我的困惑就开始了。第二个 Identity
提供所有用户声明,包括角色。
我对身份框架的理解是,我应该有一个具有两个身份的 ClaimsPrincipal
,这样我就可以插入身份框架的其余部分。但是,对于两个身份,默认 ClaimsPrincipal
将自动 select 第一个身份(这是我不能使用的身份),因此我似乎应该创建一个自定义 ClaimsPrincipal
并设置 PrimaryIdentitySelector
这样我的第二个身份就是主要身份。
public class MyClaimsPrincipal : ClaimsPrincipal
{
private static readonly Func<IEnumerable<ClaimsIdentity>, ClaimsIdentity> IdentitySelector = SelectPrimaryIdentity;
/// <summary>
/// This method iterates through the collection of ClaimsIdentities and chooses an identity as the primary.
/// </summary>
private static ClaimsIdentity SelectPrimaryIdentity(IEnumerable<ClaimsIdentity> identities)
{
// Find and return the second identity
}
}
从 OIDC IdP 获得经过验证的令牌后,我获取第二个身份,创建一个新的 MyClaimsPrincipal,将这两个身份添加到新主体。之后我不确定如何处理这个新校长。
我尝试通过 SignInManager
使用户登录,在 HTTP 上下文中明确设置用户,并使用中间件将 ClaimsPrincipals
转换为 MyClaimsPrincipals
但所有这些似乎什么都不做。我想我没抓住要点。
一些具体问题:
- 这是最好的方法吗?通常对所有这些感到困惑,所以很难判断我是否走在正确的轨道上。
- 创建自定义主体后,如何将其 "set" 放入 HTTP 上下文中以使其持久化?
- Cookie 身份验证如何与 OpenId Connect 身份验证一起使用?似乎 OIDC 以某种方式将用户传递给 Cookie 身份验证,并且需要添加 cookie 身份验证才能使 OIDC 身份验证工作。
使用 OpenID Connect 方案时要知道的一件重要事情是,该方案永远不会单独工作。在几乎每个示例中,您都会发现它与 cookie 方案相结合。原因很简单:OIDC 用于通过外部身份验证提供程序对用户进行身份验证。但这种认证只是暂时的。为了将其本地存储在您的应用程序中,您需要登录您的用户。这通常是通过 cookie 身份验证方案完成的(尽管可以通过其他方式完成)。
使用 OIDC 和 cookie 的应用程序的身份验证流程通常如下所示:
- 用户访问您的应用程序。
- Authentication: cookie 方案,默认的身份验证方案,将尝试对用户进行身份验证。如果没有 cookie,处理程序将挑战 身份验证。
- Challenge:OIDC方案,默认的挑战方案,将挑战用户并重定向到外部认证提供商。
- 用户将通过外部身份验证提供程序进行身份验证,并将被重定向回应用程序。
- 挑战回调:OIDC 方案将从外部身份验证提供程序获取响应,完成挑战并创建声明主体。
- 登录:OIDC 方案将使用其配置的登录方案(cookie 方案)登录该主体。
- cookie 方案将登录用户并创建一个 cookie,该 cookie 会持久保存在用户的浏览器中。
- 在对您的应用程序的后续请求中,用户将包含一个有效的 cookie,因此 cookie 方案可以成功验证用户身份,而无需再次挑战 OIDC 方案。
所以假设一切正常,OIDC方案将不会再次参与认证。相反,每次都会使用来自 cookie 的身份。
您可以使用它来扩展 OIDC 方案创建的具有附加声明的主体,然后再由 cookie 方案登录和保留。您可以使用位于 OIDC 和 cookie 方案之间的自定义登录方案来执行此操作,或者您可以简单地附加到在挑战 之后调用的 OIDC 方案的身份验证事件已完成,但 在 之前登录。
您可以将 TicketReceived
event 用于此目的:
public void ConfigureServices(IServiceCollection services)
{
// …
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
// …
options.Events.OnTicketReceived = OnOpenIdConnectTicketReceived;
});
}
public static Task OnOpenIdConnectTicketReceived(TicketReceivedContext context)
{
if (context.Principal.Identity is ClaimsIdentity identity)
{
identity.AddClaim(new Claim("foo", "bar"));
}
return Task.CompletedTask;
}
我仍在学习身份框架,并且在我的 .Net Core 2 MVC 应用程序中尝试设置身份验证时非常迷茫。感谢任何建议,因为我什至不确定我在做什么是正确的。
我需要为 身份验证 集成一个 OpenID Connect 身份提供者,并为 授权 使用辅助数据源。不方便的是,除了名称声明外,我不能使用 OIDC IdP 的任何声明。其余用户声明必须来自辅助数据源(通过自定义 UserStore
和 User
实体连接到身份框架)。
我正在使用 OpenId Connect provider 来处理身份验证。这工作正常并给了我第一个身份(我只能使用一个声明)。当我需要获取用户的第二个身份、将其添加到主体并将其设置为默认值 Identity
时,我的困惑就开始了。第二个 Identity
提供所有用户声明,包括角色。
我对身份框架的理解是,我应该有一个具有两个身份的 ClaimsPrincipal
,这样我就可以插入身份框架的其余部分。但是,对于两个身份,默认 ClaimsPrincipal
将自动 select 第一个身份(这是我不能使用的身份),因此我似乎应该创建一个自定义 ClaimsPrincipal
并设置 PrimaryIdentitySelector
这样我的第二个身份就是主要身份。
public class MyClaimsPrincipal : ClaimsPrincipal
{
private static readonly Func<IEnumerable<ClaimsIdentity>, ClaimsIdentity> IdentitySelector = SelectPrimaryIdentity;
/// <summary>
/// This method iterates through the collection of ClaimsIdentities and chooses an identity as the primary.
/// </summary>
private static ClaimsIdentity SelectPrimaryIdentity(IEnumerable<ClaimsIdentity> identities)
{
// Find and return the second identity
}
}
从 OIDC IdP 获得经过验证的令牌后,我获取第二个身份,创建一个新的 MyClaimsPrincipal,将这两个身份添加到新主体。之后我不确定如何处理这个新校长。
我尝试通过 SignInManager
使用户登录,在 HTTP 上下文中明确设置用户,并使用中间件将 ClaimsPrincipals
转换为 MyClaimsPrincipals
但所有这些似乎什么都不做。我想我没抓住要点。
一些具体问题:
- 这是最好的方法吗?通常对所有这些感到困惑,所以很难判断我是否走在正确的轨道上。
- 创建自定义主体后,如何将其 "set" 放入 HTTP 上下文中以使其持久化?
- Cookie 身份验证如何与 OpenId Connect 身份验证一起使用?似乎 OIDC 以某种方式将用户传递给 Cookie 身份验证,并且需要添加 cookie 身份验证才能使 OIDC 身份验证工作。
使用 OpenID Connect 方案时要知道的一件重要事情是,该方案永远不会单独工作。在几乎每个示例中,您都会发现它与 cookie 方案相结合。原因很简单:OIDC 用于通过外部身份验证提供程序对用户进行身份验证。但这种认证只是暂时的。为了将其本地存储在您的应用程序中,您需要登录您的用户。这通常是通过 cookie 身份验证方案完成的(尽管可以通过其他方式完成)。
使用 OIDC 和 cookie 的应用程序的身份验证流程通常如下所示:
- 用户访问您的应用程序。
- Authentication: cookie 方案,默认的身份验证方案,将尝试对用户进行身份验证。如果没有 cookie,处理程序将挑战 身份验证。
- Challenge:OIDC方案,默认的挑战方案,将挑战用户并重定向到外部认证提供商。
- 用户将通过外部身份验证提供程序进行身份验证,并将被重定向回应用程序。
- 挑战回调:OIDC 方案将从外部身份验证提供程序获取响应,完成挑战并创建声明主体。
- 登录:OIDC 方案将使用其配置的登录方案(cookie 方案)登录该主体。
- cookie 方案将登录用户并创建一个 cookie,该 cookie 会持久保存在用户的浏览器中。
- 在对您的应用程序的后续请求中,用户将包含一个有效的 cookie,因此 cookie 方案可以成功验证用户身份,而无需再次挑战 OIDC 方案。
所以假设一切正常,OIDC方案将不会再次参与认证。相反,每次都会使用来自 cookie 的身份。
您可以使用它来扩展 OIDC 方案创建的具有附加声明的主体,然后再由 cookie 方案登录和保留。您可以使用位于 OIDC 和 cookie 方案之间的自定义登录方案来执行此操作,或者您可以简单地附加到在挑战 之后调用的 OIDC 方案的身份验证事件已完成,但 在 之前登录。
您可以将 TicketReceived
event 用于此目的:
public void ConfigureServices(IServiceCollection services)
{
// …
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
// …
options.Events.OnTicketReceived = OnOpenIdConnectTicketReceived;
});
}
public static Task OnOpenIdConnectTicketReceived(TicketReceivedContext context)
{
if (context.Principal.Identity is ClaimsIdentity identity)
{
identity.AddClaim(new Claim("foo", "bar"));
}
return Task.CompletedTask;
}