c# - IdentityServer4 和 ASP.Net 身份 : Adding additional claims

标签 c# asp.net identityserver4

我正在尝试将 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/

相关文章:

c# - 将 ASP.NET 2.0 GridView 绑定(bind)到我自己的 IList<T>.SomeMemberOfMyOwnCustomType.SomeProperty

c# - 为什么在 ASP.NET 5 上更新到 beta8 后 Cors 不起作用?

azure - 如何使用 IdentityServer4 的 Azure 证书

c# - 在通用列表的 ForEach() 的 lambda 表达式中使用条件运算符?

c# - 如何从Windows8中的图像文件创建可写位图图像

c# - 为什么连续抛出2个异常不会产生无法访问的代码警告?

asp.net - 如何在 mvc .net Web 应用程序中从 jquery(在自定义 View 页面中)调用 Controller 后操作

asp.net-mvc - 在 .Net Framework 旧版应用程序中使用 session cookie 和/或 JWT 不记名 token 进行身份验证

c# - IdentityServer4 - API 的用户权限

c# - 限制 .net 插件可以访问的内容