ASP.NET 身份角色声明缺失

ASP.NET Identity Role claims missing

我正在使用 Duende IdentityServer 通过 Google 登录,它也配置为使用 ASP.NET 用户角色身份等

Google IdentityServer 配置:

            .AddGoogle(options =>
            {
                options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
                options.ClientId = "redacted"
                options.ClientSecret = "redacted";

            });

Blazor UI 授权配置:

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})

    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme,
        options =>
        {
            options.Authority = "myidentityserverurl";

            options.ClientId = "web2";
            options.ClientSecret = "secret";
            options.UsePkce = true;
            options.ResponseType = "code";            
            options.Scope.Add("api1");
            options.Scope.Add("roles");
            options.ClaimActions.MapUniqueJsonKey("role", "role");
            options.ClaimActions.MapUniqueJsonKey("roles", "role");

            options.TokenValidationParameters = new TokenValidationParameters
            {
                RoleClaimType = JwtClaimTypes.Role,
                ValidateAudience = false
            };
            options.SaveTokens = true;
            options.GetClaimsFromUserInfoEndpoint = true;
        });

API 授权配置:

builder.Services.AddAuthentication("Bearer")
    .AddJwtBearer(options =>
    {        
        options.Authority = "myidentityserverurl";
        options.Audience = "api1";

        options.TokenValidationParameters = new TokenValidationParameters
        {
            RoleClaimType = JwtClaimTypes.Role,
            ValidateAudience = false
        };
    });

我有一个 Blazor UI 客户端,它可以通过 Google 成功登录,它返回一个 Cookie、一个 access_token 和一个 id_token.

从 Google 登录返回的 access_token 没有来自 ASP.NET 身份的任何 role 声明,无论是来自 Blazor 还是来自 Postman。

如果我在通过 google 登录后在 IdentityServer 中调用 /connect/userinfo,我会按预期获得我所处的角色:

{
    "sub": "subhere",
    "name": "myname",
    "role": "SystemAdministrator",
    "preferred_username": "uuid from google"
}

在 Blazor 应用程序中,如果我从 httpContextAccessor.HttpContext.User.Claims 获得声明,我会按预期获得 role 声明。

如果我使用作为登录 UI 的一部分发出的访问令牌调用我的 API,并得到如下声明:

    public IActionResult Get()
    {
        return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
    }

我在这里没有任何 role 声明。同样,在通过 Google.

登录后,Postman 的不记名令牌中也没有 role 声明

以下是 API 的声明,缺少我的 role 声明:

[
  {
    "type": "iss",
    "value": "myidentityserverurl"
  },
  {
    "type": "nbf",
    "value": "1653401427"
  },
  {
    "type": "iat",
    "value": "1653401427"
  },
  {
    "type": "exp",
    "value": "1653405027"
  },
  {
    "type": "aud",
    "value": "https://myidentityserverurl/resources"
  },
  {
    "type": "scope",
    "value": "openid"
  },
  {
    "type": "scope",
    "value": "profile"
  },
  {
    "type": "scope",
    "value": "api1"
  },
  {
    "type": "scope",
    "value": "roles"
  },
  {
    "type": "http://schemas.microsoft.com/claims/authnmethodsreferences",
    "value": "external"
  },
  {
    "type": "client_id",
    "value": "web2"
  },
  {
    "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
    "value": "uuidhere"
  },
  {
    "type": "auth_time",
    "value": "1653401425"
  },
  {
    "type": "http://schemas.microsoft.com/identity/claims/identityprovider",
    "value": "Google"
  },
  {
    "type": "sid",
    "value": "A9E0A3B55D35FDAE3A7DCA0126C34E75"
  },
  {
    "type": "jti",
    "value": "43C218D3076EA595B4647CD7B369C405"
  }
]

我已经尝试了几天来修复,但我 运行 没有想法。我想我在这里遗漏了一些基本的东西。

我想你可以阅读相关文档: http://docs.identityserver.io/en/latest/reference/profileservice.html#profile-service

并尝试如下:

public class ProfileServices : IProfileService
    {
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly RoleManager<ApplicationRole> _roleManager;
        public ProfileServices(
            UserManager<ApplicationUser> userManager,
            RoleManager<ApplicationRole> roleManager)
        {
            _userManager = userManager;
            _roleManager = roleManager;
        }
 
        public async Task<List<Claim>> GetClaimsFromUserAsync(ApplicationUser user)
        {
            var claims = new List<Claim> {
                new Claim(JwtClaimTypes.Subject,user.Id.ToString()),
                new Claim(JwtClaimTypes.PreferredUserName,user.UserName)
            };
 
            var role = await _userManager.GetRolesAsync(user);
            role.ToList().ForEach(f =>
            {
                claims.Add(new Claim(JwtClaimTypes.Role, f));
            });    
            
           
            return claims;
        }
 
        
        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            var subjectId = context.Subject.Claims.FirstOrDefault(c => c.Type == "sub").Value;
            var user = await _userManager.FindByIdAsync(subjectId);
            context.IssuedClaims =await GetClaimsFromUserAsync(user);
        }
 
        
        public async Task IsActiveAsync(IsActiveContext context)
        {
            var subjectId = context.Subject.Claims.FirstOrDefault(c => c.Type == "sub").Value;
            var user = await _userManager.FindByIdAsync(subjectId);
            context.IsActive = user != null; 
        }
    }

在startup.cs中注册:

services.AddScoped<IProfileService, ProfileService>();