为什么.Net Core有自己的声明类型?

时间:2016-10-05 22:43:19

标签: 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核心应用程序正在使用OpenIdConnect进行身份验证。成功进行身份验证后,OpenIdConnect提供程序会将该角色作为声明集合的一部分发回,Cliam.Type设置为role,这符合OpenId规范。

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

为什么.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 (可以找到更多详细信息{{3在Claims Transformation部分下)
但是,当使用ASP.NET Core开发客户端应用程序时,情况并非如此。 .net核心不会将声明类型转换为.Net声明类型,这是正确的。但是.Net Core内部使用.Net声明类型来查找用户的角色声明。

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

3 个答案:

答案 0 :(得分:1)

标准惯例是什么?您只是从OpenId Connect规范的上下文中考虑它,而OpenId Connect规范并不是唯一的身份标准。微软已经足够通用以支持所有身份系统。

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

说过你可以通过实施自己的ClaimsPrincipal来修复它,并覆盖IsInRole()方法以使用正确的声明类型。

答案 1 :(得分:1)

或者您可以考虑根据OpenId声明的内容,在某个地方放置一些中间件以应用适当的角色声明?

答案 2 :(得分:0)

您可以在应用程序启动期间配置声明类型。

services.AddIdentity<ApplicationUser, IdentityRole>(options => {
        options.ClaimsIdentity.RoleClaimType = "http://yourdesiredclaimtype";
        options.ClaimsIdentity.UserNameClaimType = "http://yourdesiredclaimtype";
});

您可以在GitHub上看到claim options