虽然我很高兴IdentityServer4存在并且在许多方面使我在身份验证方面的生活变得更加容易,但我偶然发现了问题以及在社区中为声明添加角色的许多讨论.
我的要求很简单:
我开发了需要身份验证和授权的应用程序(xamarin表单)
我需要一个系统来存储我的用户的身份(名称,密码,角色,电话...) - > ASP.net身份
我需要一个系统来验证我的用户 - > IdentityServer 4
每个用户的角色非常有限(用户/管理员),不会更改
我需要一个API后端和一个MVC管理站点(asp.net核心)
我想使用[Authorize(Roles ="Admin")]限制对某些API/MVC控制器的访问
我花了无数个小时尝试不同的配置,以便在认证后将asp.net Identity角色传递给我的MVC应用程序,但没有运气.目的如第6点所述.
我也花了无数个小时阅读,但我感觉自版本v1.0.0以来,关于角色的实现IdentityServer4.AspIdentity已经发生了很大的变化.
在阅读了很多关于这一点后,仍然不清楚如何实际实现这一点,因为似乎仅在2个月前描述的一些解决方案不再有效.
所以,现在我相信有两条路:
仅通过请求身份令牌并使用AlwaysIncludeInIdToken将角色置于身份令牌中?
让客户端使用userinfo端点检索角色,并以某种方式将它们注入到httpcontext(?)中,使用[Authorize(Roles ="Admin")]来检查mvc?
无论如何,这是我的假设.
那么,请详细帮助解释/记录,以便我们能够以持久的方式开始实施吗?一些可行的例子也很棒.
因此,经过调查,我提出了两种方法来做到这一点:
在Identity Server端包含角色/其他声明
在客户端包含角色/其他声明
包含在Identity Server端
ravi punjwani在"如何使用带有IdentityServer4的ASP.Net标识添加要包含在access_token中的其他声明"中提供了答案.他的解决方案仍在草案中,但解决方案允许您在令牌发送回客户端之前添加任何声明.这是链接:如何使用带有IdentityServer4的ASP.Net标识添加要包含在access_token中的其他声明
包括在客户端
这个问题有点困难,因为它涉及在客户端的请求管道中添加"IClaimsTransformer".结果是,每个请求,Claimstransformer将检索用户的声明并将其添加到用户身份声明(令牌).Claimstransformer的设置并不容易,因为让DI工作很棘手,但经过大量研究后,celow解决方案为我做了这件事.
Custom ClaimsTransformer类在中间件中进行转换:公共类KarekeClaimsTransformer:IClaimsTransformer {private readonly UserManager _userManager;
public KarekeClaimsTransformer(UserManageruserManager) { _userManager = userManager; } public async Task 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(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); ... services.AddScoped (); // 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(); return transformer.TransformAsync(context); }); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "api/{controller}/{action?}/{id?}"); }); }