如何仅通过 userinfo 端点而不是在访问令牌中获取声明
How to get claims only via userinfo endpoint and not in the access token
我想通过 userinfo 端点获取自定义声明。这也有效,但所有自定义声明也在访问令牌中。我是这样理解的,有可能我可以在访问令牌中放置一个或两个声明(如电子邮件或姓名),而所有其他声明(given_name,...)都可以通过用户信息端点。 (并且它们不在访问令牌中)
我的 ProfileService 看起来像这样:
public class ProfileService : IProfileService
{
private readonly IUserClaimsPrincipalFactory<CustomUser> _claimsFactory;
private readonly UserManager<CustomUser> _userManager;
public ProfileService(UserManager<CustomUser> userManager, IUserClaimsPrincipalFactory<CustomUser> claimsFactory)
{
_claimsFactory = claimsFactory;
_userManager = userManager;
}
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.FirstName));
context.IssuedClaims = claims;
}
public async Task IsActiveAsync(IsActiveContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(sub);
context.IsActive = user != null;
}
}
这是我的 config.cs 文件:
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResources.Email(),
};
}
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1", "My API", new [] {JwtClaimTypes.Name })
};
}
new Client
{
ClientId = "xxx",
ClientName = "xxx",
//AccessTokenType = AccessTokenType.Reference,
AccessTokenType = AccessTokenType.Jwt,
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RequireConsent = false,
RedirectUris = { "http://localhost:4200/home" },
PostLogoutRedirectUris = { "http://localhost:4200/unauthorized" },
AllowedCorsOrigins = { "http://localhost:4200" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"api1"
}
}
};
我是不是看错了?
GetProfileDataAsync
被调用两次,但上下文不同。
- 对于访问令牌
Context.Caller
= ClaimsProviderAccessToken.
- 对于身份令牌
Context.Caller
= UserInfoEndpoint.
请注意,对于这两种情况,请求的声明有所不同。
如果您只想为身份添加声明,您可以通过将这些声明添加到过滤器 (IdentityResource) 来将这些声明配置为包含这些声明,在这种情况下,您不需要在 GetProfileDataAsync
完全没有。或者,如果您想添加特定声明,请检查当前上下文。
所以在 GetProfileDataAsync
中你可以有如下内容:
if (Context.Caller == "UserInfoEndpoint")
claims.Add(new Claim(JwtClaimTypes.GivenName, user.FirstName));
这应该只将声明添加到用户信息中。
我想通过 userinfo 端点获取自定义声明。这也有效,但所有自定义声明也在访问令牌中。我是这样理解的,有可能我可以在访问令牌中放置一个或两个声明(如电子邮件或姓名),而所有其他声明(given_name,...)都可以通过用户信息端点。 (并且它们不在访问令牌中)
我的 ProfileService 看起来像这样:
public class ProfileService : IProfileService
{
private readonly IUserClaimsPrincipalFactory<CustomUser> _claimsFactory;
private readonly UserManager<CustomUser> _userManager;
public ProfileService(UserManager<CustomUser> userManager, IUserClaimsPrincipalFactory<CustomUser> claimsFactory)
{
_claimsFactory = claimsFactory;
_userManager = userManager;
}
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.FirstName));
context.IssuedClaims = claims;
}
public async Task IsActiveAsync(IsActiveContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(sub);
context.IsActive = user != null;
}
}
这是我的 config.cs 文件:
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
new IdentityResources.Email(),
};
}
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
new ApiResource("api1", "My API", new [] {JwtClaimTypes.Name })
};
}
new Client
{
ClientId = "xxx",
ClientName = "xxx",
//AccessTokenType = AccessTokenType.Reference,
AccessTokenType = AccessTokenType.Jwt,
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RequireConsent = false,
RedirectUris = { "http://localhost:4200/home" },
PostLogoutRedirectUris = { "http://localhost:4200/unauthorized" },
AllowedCorsOrigins = { "http://localhost:4200" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"api1"
}
}
};
我是不是看错了?
GetProfileDataAsync
被调用两次,但上下文不同。
- 对于访问令牌
Context.Caller
= ClaimsProviderAccessToken. - 对于身份令牌
Context.Caller
= UserInfoEndpoint.
请注意,对于这两种情况,请求的声明有所不同。
如果您只想为身份添加声明,您可以通过将这些声明添加到过滤器 (IdentityResource) 来将这些声明配置为包含这些声明,在这种情况下,您不需要在 GetProfileDataAsync
完全没有。或者,如果您想添加特定声明,请检查当前上下文。
所以在 GetProfileDataAsync
中你可以有如下内容:
if (Context.Caller == "UserInfoEndpoint")
claims.Add(new Claim(JwtClaimTypes.GivenName, user.FirstName));
这应该只将声明添加到用户信息中。