关于asp.net核心:通过AddIdentityServer向IdentityServer设置添加声明

Adding claims to IdentityServer setup by AddIdentityServer

我有一个SPA,它具有ASP.NET Core Web API以及使用AddIdentityServerAddIdentityServerJwt打开的内置身份服务器:

1
2
3
4
services.AddIdentityServer()
   .AddApiAuthorization<User, UserDataContext>();
services.AddAuthentication()
   .AddIdentityServerJwt();

我还具有需要"管理员"角色声明的授权策略设置:

1
2
3
4
services.AddAuthorization(options =>
{
    options.AddPolicy("IsAdmin", policy => policy.RequireClaim(ClaimTypes.Role,"Admin"));
});

我有一个使用此策略的控制器操作

1
2
3
4
5
6
[Authorize(Policy ="IsAdmin")]
[HttpDelete("{id}")]
public IActionResult Deleten(int id)
{
    ...
}

经过身份验证的用户确实具有"管理员"角色声明:

enter image description here

该身份验证用户的访问令牌似乎不包含管理员声明:

enter image description here

尝试向管理员用户请求此资源时,我收到了403的回信:

enter image description here

因此,如果我正确理解这一点,则IdentityServer不包括管理员角色声明,因此用户无权访问该资源。

是否可以使用AddIdentityServerJwt配置IdentityServer使用的声明? 还是我误解了为什么这不起作用。


在Identity Server方面,可以创建配置文件服务,以在颁发令牌时使IDS4包含role声明。

您可以从ClaimsPrincipal获取角色声明,或者从数据库获取角色并创建个人档案服务,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MyProfileService : IProfileService
{
    public MyProfileService()
    { }

    public Task GetProfileDataAsync(ProfileDataRequestContext context)
    {
        //get role claims from ClaimsPrincipal
        var roleClaims = context.Subject.FindAll(JwtClaimTypes.Role);

        //add your role claims
        context.IssuedClaims.AddRange(roleClaims);
        return Task.CompletedTask;
    }

    public Task IsActiveAsync(IsActiveContext context)
    {
        // await base.IsActiveAsync(context);
        return Task.CompletedTask;
    }
}

并在Startup.cs中注册:

1
services.AddTransient<IProfileService, MyProfileService>();

在客户端,您应该从JWT令牌映射角色声明,并尝试在AddOpenIdConnect中间件中的config下面进行配置:

1
2
  options.ClaimActions.MapJsonKey("role","role","role");
  options.TokenValidationParameters.RoleClaimType ="role";

然后,您的api可以验证访问令牌并使用角色策略进行授权。


我这样做时没有使用角色,而是使用了添加到用户令牌中的特殊声明。 我创建了一个CustomUserClaimsPrincipalFactory,这使我可以向用户添加其他声明。

寄存器

1
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, CustomUserClaimsPrincipalFactory>();

代码。

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
32
33
34
35
36
public class CustomUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, IdentityRole<long>>
    {
        public CustomUserClaimsPrincipalFactory(
            UserManager<ApplicationUser> userManager,
            RoleManager<IdentityRole<long>> roleManager,
            IOptions<IdentityOptions> optionsAccessor)
            : base(userManager, roleManager, optionsAccessor)
        {
        }

        protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
        {  
            var userId = await UserManager.GetUserIdAsync(user);
            var userName = await UserManager.GetUserNameAsync(user);
            var id = new ClaimsIdentity("Identity.Application",
                Options.ClaimsIdentity.UserNameClaimType,
                Options.ClaimsIdentity.RoleClaimType);
            id.AddClaim(new Claim(Options.ClaimsIdentity.UserIdClaimType, userId));
            id.AddClaim(new Claim(Options.ClaimsIdentity.UserNameClaimType, user.Name));
            id.AddClaim(new Claim("preferred_username", userName));
            id.AddClaim(new Claim("culture", user.Culture ??"da-DK"));
            if (UserManager.SupportsUserSecurityStamp)
            {
                id.AddClaim(new Claim(Options.ClaimsIdentity.SecurityStampClaimType,
                    await UserManager.GetSecurityStampAsync(user)));
            }
            if (UserManager.SupportsUserClaim)
            {
                id.AddClaims(await UserManager.GetClaimsAsync(user));
            }

            if(user.IsXenaSupporter)
               id.AddClaim(new Claim("supporter", user.Id.ToString()));
            return id;
        }
    }

政策

1
2
3
4
services.AddAuthorization(options =>
            {
                options.AddPolicy("Supporter", policy => policy.RequireClaim("supporter"));
            });

用法

1
2
3
4
5
6
7
8
    [Authorize(AuthenticationSchemes ="Bearer", Policy ="Supporter")]
    [HttpPost("supporter")]
    public async Task<ActionResult> ChangeToSpecificUser([FromBody] ChangeUserRequest request)
    {

     // ..................

    }