我正在使用带有JWT和ASP.NET Core 2的IdentityServer4进行身份验证。由于大查询的性能问题,我还使用IdentityUser<long>
(long
主键而不是string
)作为用户模型。这就是我在编码的访问令牌中获得了一个默认为public的有序用户ID。使用GUID作为默认类型有它的原因,因此我想要公开只给出GUID,而不是有序整数。为此,我有一个GUID类型的额外ExternalID
列,在创建用户时将生成一次。
现在我需要替换sub
声明,默认情况下整数Id
与ExternalId
(GUID)一起使用。
我尝试使用ProfileService
使用以下GetProfileDataAsync
方法
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.Where(
claim =>
claim.Type != "sub" &&
context.RequestedClaimTypes.Contains(claim.Type))
.ToList();
claims.Add(new Claim("sub", user.ExternalId.ToString()));
context.IssuedClaims = claims;
}
Startup.cs
services.AddIdentityServer()
// ...
.AddProfileService<ProfileService>();
但这没有效果。 IssuedClaims
似乎被忽略了。该令牌仍包含Id
sub
声明而非ExternalId
。
我错过了什么?这是正确的做法吗?
答案 0 :(得分:0)
尽管上面有我的评论,但我仍然能够做到这一点,并且没有副作用。至少我看不到。您将需要在两个位置替换子声明。
首先像这样扩展Microsoft.AspNetCore.Identity.UserClaimsPrincipleFactory。这将在收到ID令牌之前修改声明。
CREATE FUNCTION [dbo].[GetItemMTDIssues]
(@fac char(20), @partno char(25), @rev char(3), @currentdate datetime)
returns numeric (15,5)
as
begin
declare @returnval as numeric (15,5)
set @returnval =
isnull(
(select sum(fQty)
from intran
where ftype = 'I'
and month(fdate) = month(@currentdate)
and year(fdate) = year(@currentdate)
and fac = @fac
and fpartno = @partno
and fcpartrev = @rev)
,0.0) * -1
return @returnval
end
第二个扩展IdentityServer4.Services.DefaultClaimsService像这样。这将解决我在上面的评论中提到的问题。
public sealed class MyUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, ApplicationRole>
{
public MyUserClaimsPrincipalFactory(UserManager userManager, RoleManager<ApplicationRole> roleManager, IOptions<IdentityOptions> optionsAccessor)
: base(userManager, roleManager, optionsAccessor)
{}
protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
{
var identity = await base.GenerateClaimsAsync(user);
var sub = identity.FindFirst("sub");
if (sub == null)
return identity;
identity.RemoveClaim(sub);
identity.AddClaim(new Claim("sub", user.GlobalUid.ToString()));
return identity;
}
}
添加Microsoft.AspNetCore.Identity时,通过身份生成器将UserClaimsPrincipleFactory添加到服务集合中
public class MyClaimsService : DefaultClaimsService
{
private readonly UserManager _userManager;
public MyClaimsService(IProfileService profile, ILogger<DefaultClaimsService> logger, UserManager userManager) : base(profile, logger)
{
_userManager = userManager;
}
protected override IEnumerable<Claim> GetStandardSubjectClaims(ClaimsPrincipal subject)
{
var sub = subject.GetSubjectId();
var user = _userManager.FindByIdAsync(sub).GetAwaiter().GetResult();
var claims = new List<Claim>
{
new Claim(JwtClaimTypes.Subject, user?.GlobalUid.ToString() ?? sub),
new Claim(JwtClaimTypes.AuthenticationTime, subject.GetAuthenticationTimeEpoch().ToString(), ClaimValueTypes.Integer),
new Claim(JwtClaimTypes.IdentityProvider, subject.GetIdentityProvider())
};
claims.AddRange(subject.GetAuthenticationMethods());
return claims;
}
}
然后将ClaimsService添加为类似这样的过渡
services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
{
options.User.RequireUniqueEmail = true;
options.SignIn.RequireConfirmedEmail = true;
})
.AddClaimsPrincipalFactory<MyUserClaimsPrincipalFactory>()
现在,您所有的债权应作为您为所有令牌提供的属性返回。如果您对此有任何疑问,请告诉我,因为它仍在测试阶段。