提问者:小点点

。Net Core 2 OpenID连接认证和多重身份


我仍在学习身份框架,在我的.Net Core 2 MVC应用程序中尝试设置身份验证时,我非常迷失了方向。任何建议都很感激,因为我甚至不确定自己所做的是正确的。

我需要集成OpenID Connect身份提供程序进行身份验证,并使用辅助数据源进行授权。不方便的是,除了名称声明之外,我不能使用OIDC IdP的任何声明。其余的用户声明必须来自辅助数据源(通过自定义的UserStoreuser实体连接到Identity Framework)。

我正在使用OpenId Connect提供程序来处理身份验证。这工作正常,并给了我第一个身份(我只能使用一个声明)。当我需要获取用户的第二个标识,将其添加到主体并将其设置为默认标识时,我的困惑就开始了。第二个标识提供所有用户声明,包括角色。

我对身份框架的理解是,我应该有一个带有两个身份的ClaimsPrincipal,这样我就可以插入身份框架的其余部分。然而,对于两个身份,默认的ClaimsPrincipal将自动选择第一个身份(这是我不能使用的一个),因此我似乎应该创建一个自定义的ClaimsPrinccipal并设置PrimaryIdentity Selector,以便我的第二个身份是主要身份。

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转换为MyClaimsPrinccipals,但所有这些似乎都无济于事。我想我没有抓住重点。

一些具体问题:

  • 这是最好的方法吗?对这一切普遍感到困惑,很难判断我是否走在正确的轨道上。
  • 创建自定义主体后,如何将其“设置”到 HTTP 上下文中,使其持久化?
  • Cookie 身份验证如何与 OpenId Connect 身份验证配合使用?似乎 OIDC 以某种方式将用户传递到 Cookie 身份验证,并且需要添加 cookie 身份验证才能使 OIDC 身份验证正常工作。

共1个答案

匿名用户

使用OpenID Connect方案时需要知道的一件重要事情是,该方案永远不会单独工作。在你能找到的几乎每一个例子中,你都会看到它与cookie方案相结合。原因很简单:OIDC用于通过外部身份验证提供者对用户进行身份验证。但这种身份验证只是暂时的。为了在应用程序中本地存储它,您需要登录您的用户。这通常是通过cookie身份验证方案来完成的(尽管也可以通过其他方式来完成)。

使用OIDC和cookie的应用程序的身份验证流程通常如下所示:

  1. 用户访问您的应用程序
  2. 身份验证:默认的身份验证方案cookie方案将尝试对用户进行身份验证。如果没有cookie,处理程序将对身份验证提出质疑
  3. 挑战:OIDC方案是默认的挑战方案,它将挑战用户并重定向到外部身份验证提供商
  4. 用户将通过外部身份验证提供程序进行身份验证,并将重定向回应用程序
  5. 质询回调:OIDC方案将从外部身份验证提供程序获取响应,完成质询并创建声明主体
  6. 登录:OIDC方案将使用其配置的登录方案(cookie方案)登录该主体
  7. cookie方案将登录用户并创建一个cookie,该cookie将保存在用户的浏览器中
  8. 在随后向您的应用程序发出请求时,用户将包含一个有效的cookie,因此cookie方案可以成功地对用户进行身份验证,而无需再次挑战OIDC方案

因此,假设一切正常,OIDC方案将不会再次参与认证。相反,每次都会使用cookie中的标识。

您可以使用它来扩展 OIDC 方案使用其他声明创建的主体,然后再由 cookie 方案登录并保留。您可以使用位于 OIDC 和 Cookie 方案之间的自定义登录方案来执行此操作,也可以简单地附加到质询完成后但在登录发生之前调用的 OIDC 方案的身份验证事件。

您可以将<code>TicketReceived</code>事件用于此目的:

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;
}