如何将ASP.net身份角色放入Identityserver4身份令牌

时间:2017-01-16 18:03:04

标签: asp.net-mvc asp.net-core identityserver4

虽然我很高兴IdentityServer4存在并且在许多方面使我在身份验证方面的生活变得更加容易,但我偶然发现了问题以及在社区中为声明添加角色的许多讨论。

我的要求很简单:

  1. 我开发需要身份验证和授权的应用程序(xamarin表单)
  2. 我需要一个系统来存储我的用户的身份(姓名,密码,角色,电话......) - > ASP.net身份
  3. 我需要一个系统来验证我的用户 - > IdentityServer 4
  4. 每位用户的角色非常有限(用户/管理员)且不会更改
  5. 我需要一个API后端和一个MVC管理站点(asp.net核心)
  6. 我想使用[授权(角色="管理员")]
  7. 限制对某些API / MVC控制器的访问

    我花了无数个小时尝试不同的配置,以便在身份验证后将asp.net Identity角色传递给我的MVC应用程序,但没有运气。目的如第6点所述。

    我也花了无数个小时阅读,但我感觉自版本v1.0.0以来,角色的实现IdentityServer4.AspIdentity已经发生了很大的变化。

    在阅读了很多相关内容后,仍然不清楚如何实际实现这一点,因为似乎仅在2个月前描述的某些解决方案不再有效。

    所以,现在我相信有两条路径:

    1. 仅通过请求身份令牌将角色置于身份令牌中 并使用AlwaysIncludeInIdToken?
    2. 让客户端检索角色 使用userinfo端点并以某种方式将它们注入到 httpcontext(?)允许mvc使用[Authorize(Roles =。)进行检查 "联系")]
    3. 无论如何,这是我的假设。

      那么,请详细帮助解释/记录,以便我们能够以持久的方式开始实施吗?一些可行的例子也很棒。

1 个答案:

答案 0 :(得分:9)

因此,经过调查,我提出了两种方法来做到这一点:

  1. 在Identity Server端包含角色/其他声明
  2. 在客户端包含角色/其他声明
  3. 包含在Identity Server端

    ravi punjwani在“如何使用带有IdentityServer4的ASP.Net标识添加要包含在access_token中的其他声明”中提供了答案。他的解决方案仍在草案中,但解决方案允许您在令牌发送回客户端之前添加任何声明。这是链接:How to add additional claims to be included in the access_token using ASP.Net Identity with IdentityServer4

    包含在客户端

    这个问题有点困难,因为它涉及在客户端的请求管道中添加“IClaimsTransformer”。结果是,每个请求,Claimstransformer将检索用户的声明并将其添加到用户身份声明(令牌)。 Claimstransformer的设置并不容易,因为让DI工作很棘手,但经过大量研究后,celow解决方案为我做了。

    Custom ClaimsTransformer类在中间件中进行转换:     公共类KarekeClaimsTransformer:IClaimsTransformer     {         private readonly UserManager _userManager;

        public KarekeClaimsTransformer(UserManager<ApplicationUser> userManager)
        {
            _userManager = userManager;
        }
    
        public async Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
        {
            if (context.Principal.Identity.IsAuthenticated)
            {
                Claim userId = context.Principal.FindFirst("sub");
    
                if (context.Principal.FindFirst("role") == null && userId != null)
                {
                    ApplicationUser user = await _userManager.FindByIdAsync(userId.Value);
                    var roles = await _userManager.GetRolesAsync(user);
                    foreach (var role in roles)
                    {
                        ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim(JwtClaimTypes.Role, role,
                            "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"));
                    }
                }
            }
            return Task.FromResult(context.Principal).Result;
        }
    }
    

    在Client启动类中,您需要将其添加到ConfigureServices

    中的范围
    public void ConfigureServices(IServiceCollection services)
        {
            // Add framework services.
            services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    
            ...
            services.AddScoped<IClaimsTransformer, KarekeClaimsTransformer>();
            // Add framework services.
            services.AddMvc();
        }
    

    最后,添加配置:

     public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();
    
            app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
            {
                Authority = "http://localhost:5000",
                RequireHttpsMetadata = false,
    
                ApiName = "api1"
            });
    
            app.UseClaimsTransformation((context) =>
            {
                IClaimsTransformer transformer = context.Context.RequestServices.GetRequiredService<IClaimsTransformer>();
                return transformer.TransformAsync(context);
            });
    
            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "api/{controller}/{action?}/{id?}");
            });
        }