簡體   English   中英

IdentityServer4 和 ASP.Net Identity:添加額外聲明

[英]IdentityServer4 and ASP.Net Identity: Adding additional claims

我正在嘗試將 IdentityServer4 與提供用戶存儲的 ASP.Net Identity Core 一起使用。 我大致遵循了本指南: https ://www.scottbrady91.com/Identity-Server/Getting-Started-with-IdentityServer-4 ,並且已經到了可以使用 ASP.Net 在本地注冊和驗證用戶的地步身份。

我的問題是我在注冊時添加了一些聲明:

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>();

我的理解是這個自定義主體工廠應該將我想要的聲明添加到用戶對象中,但這並沒有發生。 我可以看到自定義聲明主體工廠是使用構造函數中的斷點實例化的,但從未調用過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擴展方法,我可以看到它似乎注冊了某種自定義用戶聲明主體工廠,但我不太了解實現代碼,無法弄清楚到底發生了什么。

我如何實現自定義用戶聲明主要工廠,以便我可以在視圖中執行類似的操作?

// "yolo" is a custom claim
@User.FindFirst("yolo")

我解決了這個問題(至少,以一種滿足我要求的方式)。 在 quickstart 項目中執行登錄的邏輯如下所示:

...
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);
    ...
}

通過查看 IdentityServer4 添加到 HttpContext 的擴展方法,我發現有幾個方法接受聲明數組。

我修改了帳戶控制器中的登錄邏輯:

...
var userClaims = await _userManager.GetClaimsAsync(user);
await HttpContext.SignInAsync(user.Id, user.UserName, props, userClaims.toArray());
...

這成功地將所有用戶的聲明從數據庫添加到當前會話。 從這里我可以只選擇我想要的聲明,並改為傳遞這些聲明的數組。

現在所需的聲明已存儲為會話的一部分,我可以根據需要從視圖或其他控制器調用@User.FindFirst("yolo")

我還實現了類似的功能來為用戶設置聲明。

Claim claim = new Claim(claimType, claimValue, ClaimValueTypes.String);
IdentityResult result = await userManager.AddClaimAsync(user, claim);

這會在 AspNetUserClaims 表中為特定用戶添加聲明

在此處輸入圖像描述

Microsoft.AspNetCore.Identity.SignInManager提供了身份驗證的內置功能。

這也會在登錄時自動為用戶創建聲明。以下是使用SignInManager的示例登錄

[HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Login(Login login)
    {
        if (ModelState.IsValid)
        {
            AppUser appUser = await userManager.FindByEmailAsync(login.Email);
            if (appUser != null)
            {
                await signInManager.SignOutAsync();
                Microsoft.AspNetCore.Identity.SignInResult result = await signInManager.PasswordSignInAsync(appUser, login.Password, false, false);
                if (result.Succeeded)
                    return Redirect(login.ReturnUrl ?? "/");
            }
            ModelState.AddModelError(nameof(login.Email), "Login Failed: Invalid Email or password");
        }
        return View(login);
    }

用戶成功登錄后,我們可以使用Microsoft.AspNetCore.Mvc.Razor.RazorPageBase.User訪問視圖中的所有聲明

以下是檢索所有聲明的示例代碼:

     <h2>Claim details</h2>
     <ul>
        @foreach (var claim in User.Claims)
        {
           <li><strong>@claim.Type</strong>: @claim.Value</li>
        }
     </ul>

我按照本教程進行身份聲明,其中還包括管理自定義聲明

  1. https://www.yogihosting.com/aspnet-core-identity-claims/
  2. https://code-maze.com/authentication-aspnet-core-identity/

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM