asp.net-core - 为什么 .Net Core 有自己的声明类型?

标签 asp.net-core openid-connect coreclr

基于 OpenidConnect 规范,角色声明和名称声明的标准类型是 rolename。但是在 .net 核心中 System.Security.Claims.ClaimsIdentity.NameClaimType 设置为“http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name” 并且 System.Security.Claims.ClaimsIdentity.RoleClaimType 设置为“http://schemas.microsoft.com/ws/2008/06/identity/claims/role "

我的问题是角色。

我的 ASP.NET Core 应用程序使用 OpenIdConnect 进行身份验证。身份验证成功后,OpenIdConnect 提供程序发回角色作为声明集合的一部分,Cliam.Type 设置为 role,根据 OpenId 规范这是正确的。

然而,由于 .Net Core 有自己的角色类型,IsInRole() 方法总是返回 false。因为我认为 IsInRole() 方法使用微软的角色类型进行比较。

为什么 .net 对声明使用不同类型而不是使用标准约定?以及如何解决 IsInRole() 问题

更新 1

好吧,我尝试在启动期间配置声明类型,但没有成功。

startup.cs

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        // some stuff here that is not related to Identity like building configuration
    }

    public IConfigurationRoot Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        services.AddApplicationInsightsTelemetry(Configuration);
        services.AddAuthorization();
        services.AddMvc(config =>
        {
            var policy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .Build();
            config.Filters.Add(new AuthorizeFilter(policy));
        });

        // Add Kendo UI services to the services container
        services.AddKendo();

        // Transform Microsoft cliam types to my claim type
        services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
        {
            options.ClaimsIdentity.RoleClaimType = "role";
            options.ClaimsIdentity.UserNameClaimType = "name";
        });

    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IApplicationLifetime appLifetime)
    {            
        loggerFactory.AddSerilog();
        appLifetime.ApplicationStopped.Register(Log.CloseAndFlush);
        app.UseExceptionHandler("/Home/Error");
        app.UseApplicationInsightsRequestTelemetry();
        app.UseApplicationInsightsExceptionTelemetry();
        app.UseStaticFiles();

        app.UseIdentityServer(Configuration["Identity:Authority"], Configuration["Identity:ClientId"], Configuration["Identity:PostLogoutRedirectUri"]);

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });

        // Configure Kendo UI
        app.UseKendo(env);
    }
}

UseIdentityServer 扩展方法

    public static void UseIdentityServer(this IApplicationBuilder app, string authority, string clientId, string postlogoutRedirectUri)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions()
        {
            AutomaticAuthenticate = true,
            AutomaticChallenge = true,
            AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme,
            LoginPath = IdentityConstant.CallbackPath,
            AccessDeniedPath = new PathString(IdentityConstant.AccessDeniedPath),
            CookieName = IdentityConstant.AuthenticationCookieName,
        });

        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap = new Dictionary<string, string>();

        var connectOptions = new OpenIdConnectOptions()
        {         
            AutomaticChallenge = true,
            Authority = authority,
            ClientId = clientId,
            ResponseType = IdentityConstant.ResponseType,
            AuthenticationScheme = IdentityConstant.OpenIdAuthenticationScheme,
            SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme,
            PostLogoutRedirectUri = postlogoutRedirectUri,
            CallbackPath = IdentityConstant.CallbackPath,
            Events = new OpenIdConnectEvents()
            {
                OnTokenValidated = async context =>
                {
                    var userInfoClient = new UserInfoClient(context.Options.Authority + IdentityConstant.UserInfoEndpoint);
                    var response = await userInfoClient.GetAsync(context.ProtocolMessage.AccessToken);
                    var claims = response.Claims;

                    //We will create new identity to store only required claims.
                    var newIdentity = new ClaimsIdentity(context.Ticket.Principal.Identity.AuthenticationType);

                    // keep the id_token for logout
                    newIdentity.AddClaim(new Claim(IdentityConstant.IdTokenClaim, context.ProtocolMessage.IdToken));

                    // add userinfo claims
                    newIdentity.AddClaims(claims);

                    // overwrite existing authentication ticket
                    context.Ticket = new AuthenticationTicket(
                        new ClaimsPrincipal(newIdentity),
                        context.Ticket.Properties,
                        context.Ticket.AuthenticationScheme);

                    await Task.FromResult(0);
                }
            }
        };

        connectOptions.Scope.Add(IdentityConstant.OpenIdScope);
        connectOptions.Scope.Add(IdentityConstant.ProfileScope);
        connectOptions.Scope.Add("roles");

        app.UseOpenIdConnectAuthentication(connectOptions);
    }

更新 2

我使用 IdentityServer3 对我们所有的应用程序进行身份验证。如果客户端应用程序是使用经典的 ASP.NET MVC 开发的,那么 ASP.Net 的 JWT 处理程序会将传入的 role 声明类型转换为 http://schemas.microsoft.com/ws/2008/06/identity/claims/role (更多详细信息可以在 Claims Transformation 部分下找到 here)
但是,当使用 ASP.NET Core 开发客户端应用程序时,情况就不一样了。 .net 核心不会 将声明类型转换为 .Net 声明类型,这是正确的。但是 .Net Core 内部使用 .Net 声明类型来查找用户的角色声明。

这意味着我需要将 .Net 声明类型转换为所需的声明类型,但不确定在哪里?

最佳答案

什么是标准约定?您只是从 OpenId Connect 规范的上下文中考虑它,这不是唯一的身份标准。 Microsoft 已使其足够通用以支持所有身份系统。

这里的错误似乎出在 OpenId Connect 身份验证实现中,因为它没有提供使用正确的角色声明类型的 ClaimsPrincipal

话虽如此,您可以通过实现自己的 ClaimsPrincipal 并覆盖 IsInRole() 方法以使用正确的声明类型来修复它。

关于asp.net-core - 为什么 .Net Core 有自己的声明类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39884810/

相关文章:

asp.net-core - Swagger 解析器错误,无法解析引用 :

asp.net - 将 ASP.NET 4 Razor "extensionless URLs"站点移植到 ASP.NET 5

javascript - 使用隐式流程时的重放攻击

security - 使用 openid connect 作为多个应用程序的 SSO

c# - 当 native 进程托管 .NET Core 运行时时,在 C# 和 C++ 之间传递 C# 托管实例

c# - 如何在 .Net Core 中为不同的语言创建 StringComparer?

c# - 在哪里可以获得适用于 Windows 10 IoT 的 SOS?

asp.net-core - 在 Visual Studio 之外获取 .NET Core 中所有使用过的 NuGet 包的许可证信息

mysql - 如何从 Linux 上的 asp.net 核心应用程序迁移我的表

java - 身份验证重定向后如何返回 Jersey MVC Viewable?