ASP.NET Core Identity与Duende IdentityServer集成多外部身份提供程序

本文详细介绍了如何在ASP.NET Core Identity应用中集成多个外部身份提供程序,使用Duende IdentityServer实现OIDC客户端UI,包括方案配置、声明映射和IProfileService实现等技术细节。

在ASP.NET Core Identity和Duende IdentityServer中使用多个外部身份提供程序

这篇博客文章展示了ASP.NET Core Identity应用程序如何集成和实现多个外部身份提供程序。OIDC客户端UI使用该解决方案,并使用Duende IdentityServer实现。所有外部提供程序使用相同的方案,并映射到客户端UI和应用程序的身份。使用OpenID Connect,这些信息通过令牌或用户配置文件API返回给Web应用程序。

代码:https://github.com/damienbod/DuendeProfileServiceAspNetCoreIdentity

设置

该应用程序用作身份提供程序。可以用于本地用户或使用OpenID Connect联盟的外部用户。使用该应用程序的所有应用程序都与进一步的身份验证系统分离。通过使用Duende,可以使用高端OAuth和OpenID Connect身份验证流程,这些流程在其他一些知名身份提供程序中不受支持。在此设置中也可以使用OpenIddict。服务器的用户使用OpenID Connect进行身份验证。声明需要映射,每个外部身份验证提供程序也需要映射。身份回调UI用于处理所有外部身份验证流程结果。每个外部身份验证的声明不同,需要映射到封闭系统中使用的声明。

外部提供程序

在ASP.NET Core Identity中实现外部身份验证提供程序时,可以使用不同的策略。每个外部提供程序为OpenID Connect流程使用单独的方案。在成功结果时,身份可以持久化到公共外部身份会话,或者每个提供程序可以使用唯一方案。两者都有优缺点。如果全部使用相同的方案,注销和回调方案逻辑可以简单,声明映射按提供程序逻辑实现。如果每个提供程序使用单独的方案,回调和注销需要方案逻辑和检查。

在此演示中,我们遵循Duende示例的建议,使用一个方案为所有外部提供程序持久化会话。每个外部提供程序必须为身份验证流程使用特定的URL,否则状态和流程将无法正常工作,因为不同的提供程序会中断。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
builder.Services.AddAuthentication(options =>
{
   options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
   options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
   options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
}).AddOpenIdConnect("Auth0Scheme", "Auth0", options =>
{
   // SignInScheme必须与身份回调中使用的方案匹配
   options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
   options.SignOutScheme = IdentityConstants.ApplicationScheme;
       
   // 每个客户端的路径必须不同
   options.CallbackPath = new PathString("/signin-oidc-auth0");
   options.RemoteSignOutPath = new PathString("/signout-callback-oidc-auth0");
   options.SignedOutCallbackPath = new PathString("/signout-oidc-auth0");

   // 更多oidc选项...
}).AddOpenIdConnect("EntraID", "EntraID", oidcOptions =>
{
   builder.Configuration.Bind("AzureAd", oidcOptions);
   oidcOptions.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
   oidcOptions.SignOutScheme = IdentityConstants.ApplicationScheme;

   oidcOptions.CallbackPath = new PathString("/signin-oidc-entraid");
   oidcOptions.RemoteSignOutPath = new PathString("/signout-callback-oidc-entraid");
   oidcOptions.SignedOutCallbackPath = new PathString("/signout-oidc-entraid");

   // 更多oidc选项...
});

使用Microsoft.Identity.Web

如果使用Microsoft.Identity.Web Nuget包实现外部提供程序逻辑,则需要一个新的单独方案来处理回调和注销,因为AddMicrosoftIdentityWebApp扩展方法创建自己的方案,无法重用Identity定义的默认方案。然后该方案需要在回调UI和注销逻辑中实现逻辑。

Duende IProfileService

如果将ASP.NET Core Identity与OpenID Connect提供程序(如Duende IdentityServer或OpenIddict)一起使用,则需要将来自不同外部提供程序的声明映射回不同UI应用程序使用的声明。在Duende中,可以使用IProfileService映射声明。请参阅Duende文档。GetProfileDataAsync可以为UI应用程序的每次成功身份验证多次调用,每次针对不同的声明类型。使用的内容取决于OpenID Connect客户端设置。应避免为相同的值多次添加声明,并避免向身份令牌添加过多声明。映射应以相同的方式工作,无论是身份令牌映射还是客户端使用用户信息端点时。

当使用许多客户端应用程序时,应使用标准声明,不要根据多个下游外部身份验证提供程序使用不同的声明。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class ProfileService: IProfileService
{
    public async Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        // context.Subject是结果为其生成的用户
        // context.Subject.Claims是登录时用户会话cookie中的声明集合

        
        if (context.Caller == IdentityServerConstants.ProfileDataCallers.ClaimsProviderAccessToken)
        {
            // access_token
        }
        if (context.Caller == IdentityServerConstants.ProfileDataCallers.ClaimsProviderIdentityToken)
        {
            // id_token
            var oid = context.Subject.Claims.FirstOrDefault(t => t.Type == "oid");
            if(oid != null)
            {

            }
        }
        if (context.Caller == IdentityServerConstants.ProfileDataCallers.UserInfoEndpoint)
        {
            // user_info端点 
        }
        
        // 全部

        return;
    }
}

仅Identity解决方案中的声明映射

如果不使用OIDC服务器且仅使用ASP.NET Core Identity,可以实现ClaimsTransformation来映射声明。

链接

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计