我创建了多个声明,这些声明位于标识AspNetUserClaims
表中,并将它们分配给我的用户 ID。
我目前正在尝试在客户端应用程序中收到的声明列表中拉出这些内容。
通过将"角色"范围添加到我的客户端标识设置,我设法从AspNetUserRoles
表中拉取所有角色,然后在标识配置中(使用 EF 数据库格式,又名 ConfigurationDbContext(在IdentityResources
表中创建了一条记录,该记录链接到名为"role"的身份声明。
这正在按预期工作。但是,我没有获得我通过创建的任何用户声明,我是否需要创建另一个特定范围?
这是我的客户端配置:
services.AddAuthentication(options =>
{
options.DefaultScheme = "cookie";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("cookie")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "https://localhost:44335/";
options.ClientId = "openIdConnectClient";
options.SignInScheme = "cookie";
options.ResponseType = "id_token";
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Add("openid profile roles all_claims");
});
services.AddAuthorization();
这就是我检查用户拥有哪些声明的方式:
var claims = ((ClaimsIdentity)User.Identity).Claims;
它返回所有角色和配置文件声明(例如preferred_username(,但不返回 AspNetUserClaims 表中指定的那些。
对于我的客户,我也将属性[AlwaysIncludeUserClaimsInIdToken]
设置为 true,但没有运气。
有谁知道我缺少什么来传递用户声明?
您是否有 IProfileService 实现来填充自定义声明?
您应该按照本答案中的指示执行IProfileService
。
尝试除id_token
以外的其他response_type
,因为应用程序没有用于调用用户信息终结点的访问令牌。也许用id_token token
来维护客户端的隐式流授权。
您可以像这样获取用户声明:
var claims = User.Claims.Select(c => new { c.Type, c.Value });
您可以在 API 中将其实现为终端节点,您在身份服务器中将其声明为范围:
using IdentityServer4;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Linq;
namespace IdentityServer4Demo.Api
{
[Route("/api/test")]
[Authorize]
public class TestController : ControllerBase
{
public IActionResult Get()
{
var claims = User.Claims.Select(c => new { c.Type, c.Value });
return new JsonResult(claims);
}
}
}
如果要添加更多声明,则需要将属性添加到实现 IdentityUser 的类中,并在自定义配置文件服务中使用它
using Microsoft.AspNetCore.Identity;
namespace AuthServer.Infrastructure.Data.Identity
{
public class AppUser : IdentityUser
{
// Add additional profile data for application users by adding properties to this class
public string Name { get; set; }
}
}
您的自定义配置文件服务:
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using AuthServer.Infrastructure.Constants;
using AuthServer.Infrastructure.Data.Identity;
using IdentityModel;
using IdentityServer4;
using IdentityServer4.Extensions;
using IdentityServer4.Models;
using IdentityServer4.Services;
using Microsoft.AspNetCore.Identity;
namespace AuthServer.Infrastructure.Services
{
public class IdentityClaimsProfileService : IProfileService
{
private readonly IUserClaimsPrincipalFactory<AppUser> _claimsFactory;
private readonly UserManager<AppUser> _userManager;
public IdentityClaimsProfileService(UserManager<AppUser> userManager, IUserClaimsPrincipalFactory<AppUser> claimsFactory)
{
_userManager = userManager;
_claimsFactory = claimsFactory;
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(sub);
var principal = await _claimsFactory.CreateAsync(user);
var claims = principal.Claims.ToList();
claims = claims.Where(claim => context.RequestedClaimTypes.Contains(claim.Type)).ToList();
claims.Add(new Claim(JwtClaimTypes.GivenName, user.Name));
claims.Add(new Claim(IdentityServerConstants.StandardScopes.Email, user.Email));
// note: to dynamically add roles (ie. for users other than consumers - simply look them up by sub id
claims.Add(new Claim(ClaimTypes.Role, Roles.Consumer)); // need this for role-based authorization - https://stackoverflow.com/questions/40844310/role-based-authorization-with-identityserver4
context.IssuedClaims = claims;
}
}