我正在尝试将 IdentityServer4 与 ASP.Net Identity Core 一起使用来提供用户存储。我大致遵循了本指南:https://www.scottbrady91.com/Identity-Server/Getting-Started-with-IdentityServer-4 ,并且已经可以使用 ASP.Net Identity 在本地注册和验证用户。
我的问题是我在注册时添加了一些声明:
var createUserResult = await _userManager.CreateAsync(user, model.Password);
if (createUserResult.Succeeded)
{
var claims = new List<Claim>
{
new Claim(JwtClaimTypes.Email, user.Email),
new Claim(JwtClaimTypes.Role, "user"),
new Claim("test-claim", "loremipsum")
};
await _userManager.AddClaimsAsync(user, claims);
await HttpContext.SignInAsync(user.Id, user.UserName, new AuthenticationProperties());
return Redirect(model.ReturnUrl ?? "~/");
}
这些已正确保存,我可以在数据库中看到它们。但是,一旦我登录,用户对象只有以下声明:
- 子
- 姓名
- 验证时间
- 国内流离失所者
- amr
网上查了一下,似乎我需要重写 UserClaimsPrincipalFactory 并向 DI 容器注册此实现:
public class CustomUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>
{
public CustomUserClaimsPrincipalFactory(
UserManager<ApplicationUser> userManager,
RoleManager<IdentityRole> roleManager,
IOptions<IdentityOptions> options) : base(userManager, roleManager, options)
{
Console.WriteLine("Test");
}
public override async Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
{
var principal = await base.CreateAsync(user);
((ClaimsIdentity) principal.Identity).AddClaim(new Claim("yolo", "swag"));
return principal;
}
protected override async Task<ClaimsIdentity> GenerateClaimsAsync(ApplicationUser user)
{
var identity = await base.GenerateClaimsAsync(user);
identity.AddClaim(new Claim("yolo", "swag"));
return identity;
}
}
在DI容器中注册如下:
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, CustomUserClaimsPrincipalFactory>();
我的理解是,这个自定义主体工厂应该将我想要的声明添加到 User 对象中,但这不会发生。我可以看到自定义声明主体工厂是使用构造函数中的断点实例化的,但从未调用 GenerateClaimsAsync
函数。
IdentityServer 和 ASP.Net 身份注册如下:
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer(config =>
{
config.PublicOrigin = _configuration.PublicOriginUrl;
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder => builder.UseNpgsql(
_sqlConnectionString,
sqlOptions => sqlOptions.MigrationsAssembly(MigrationsAssembly));
})
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder => builder.UseNpgsql(
_sqlConnectionString,
sqlOptions => sqlOptions.MigrationsAssembly(MigrationsAssembly));
})
.AddAspNetIdentity<ApplicationUser>()
.AddDeveloperSigningCredential();
我的自定义用户声明主要工厂在此部分之后注册。查看 AddAspNetIdentity
扩展方法 here ,我可以看到它似乎注册了某种自定义用户声明主体工厂,但我对实现代码的理解不够好,无法弄清楚到底发生了什么。
如何实现自定义用户声明主体工厂,以便我可以在 View 中执行类似的操作?
// "yolo" is a custom claim
@User.FindFirst("yolo")
最佳答案
我解决了这个问题(至少,以满足我的要求的方式)。在快速入门项目中执行登录的逻辑如下所示:
...
if (user != null && await _userManager.CheckPasswordAsync(user, model.Password)) {
await _events.RaiseAsync(
new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName));
AuthenticationProperties props = null;
if (AccountOptions.AllowRememberLogin && model.RememberLogin) {
props = new AuthenticationProperties {
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
};
};
await HttpContext.SignInAsync(user.Id, user.UserName, props);
...
}
通过查看extension methods当 IdentityServer4 添加到 HttpContext 时,我发现有几个接受一系列声明。
我修改了帐户 Controller 中的登录逻辑:
...
var userClaims = await _userManager.GetClaimsAsync(user);
await HttpContext.SignInAsync(user.Id, user.UserName, props, userClaims.toArray());
...
这成功地将所有用户的声明从数据库添加到当前 session 。从这里我只能选择我想要的声明,并传递这些声明的数组。
现在所需的声明已存储为 session 的一部分,我可以根据需要从 View 或其他 Controller 调用 @User.FindFirst("yolo")
。
关于c# - IdentityServer4 和 ASP.Net 身份 : Adding additional claims,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53837999/