首页 > 解决方案 > 我们如何使用 IUserClaimsPrincipalFactory?

问题描述

我对此处文档中的示例感到困惑,该示例描述了如何使用IUserClaimsPrincipalFactory.

示例代码显示了如何扩展ApplicationUser类:

public class ApplicationUser : IdentityUser
{
    public bool IsAdmin { get; set; }
}

...然后实现一个UserClaimsPrincipalFactory测试该属性以确定要添加的声明:

if (user.IsAdmin)
{
    claims.Add(new Claim(JwtClaimTypes.Role, "admin"));
}
else
{
    claims.Add(new Claim(JwtClaimTypes.Role, "user"));
}

没有说明,但我认为这意味着其他东西(未显示)将为IsAdmin数据库中的用户设置属性。我认为他们本可以清楚地说明这一点。(此外,令人失望的是,当角色与声明之间存在如此多的混淆时,该示例使用角色,但我离题了......)

无论如何,我们已经根据该新IsAdmin属性的价值向用户添加了一些“角色”声明。到目前为止,一切都很好。我不明白的是下一点:

然后可以在应用程序中使用附加声明。在 Razor 页面中,该IAuthorizationService实例可用于访问声明值。

听起来 Razor 页面将访问我们的声明 - 但这里是代码:

@if ((await AuthorizationService.AuthorizeAsync(User, "IsAdmin")).Succeeded)
{
    ...
}

真的是在访问索赔吗?在我看来,它正在访问IsAdmin用户的属性。我根本看不到我们添加的声明是如何被引用——除非还有其他没有被解释的东西。

重载AuthorizeAsync将最后一个参数描述为“policyName”。我们是否打算假设有一个名为“IsAdmin”的策略来检查我们的新角色声明?

这是一份多么糟糕的文档——我忽略了它也在错误的地方这一事实。

标签: asp.net-core-identity

解决方案


没有说明,但我认为这意味着其他东西(未显示)将为数据库中的用户设置 IsAdmin 属性。

IsAdmin你可以设置在你想要的地方,比如你可以在注册的时候设置。这里有一个demo: 在此处输入图像描述

在寄存器中输入模型:

 public class InputModel
        {
            ...
            public bool IsAdmin { get; set; }
        }

后处理程序:

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
        {
            returnUrl ??= Url.Content("~/");
            ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
            if (ModelState.IsValid)
            {
                var user = new ApplicationUser { UserName = Input.Email, Email = Input.Email ,IsAdmin=Input.IsAdmin};
                var result = await _userManager.CreateAsync(user, Input.Password);
                if (result.Succeeded)
                {
                    _logger.LogInformation("User created a new account with password.");

                    var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
                    code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
                    var callbackUrl = Url.Page(
                        "/Account/ConfirmEmail",
                        pageHandler: null,
                        values: new { area = "Identity", userId = user.Id, code = code, returnUrl = returnUrl },
                        protocol: Request.Scheme);

                    //await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                    //    $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

                    if (_userManager.Options.SignIn.RequireConfirmedAccount)
                    {
                        return RedirectToPage("RegisterConfirmation", new { email = Input.Email, returnUrl = returnUrl });
                    }
                    else
                    {
                        await _signInManager.SignInAsync(user, isPersistent: false);
                        return LocalRedirect(returnUrl);
                    }
                }
                foreach (var error in result.Errors)
                {
                    ModelState.AddModelError(string.Empty, error.Description);
                }
            }

            // If we got this far, something failed, redisplay form
            return Page();
        }

这真的是在访问索赔吗?在我看来,它正在访问用户的 IsAdmin 属性。我根本看不到我们添加的声明是如何被引用的——除非还有其他没有被解释的东西。

AuthorizeAsync 的重载将最后一个参数描述为“policyName”。我们是否打算假设有一个名为“IsAdmin”的策略来检查我们的新角色声明?

IsAdmin是代码中的策略名称,您需要添加名称为的策略IsAdmin,并检查其中的新角色声明。

 public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
            services.AddAuthorization(options =>
            {
                options.AddPolicy("IsAdmin", policy => policy.RequireClaim("role", "admin"));
            });
        } 

结果: 在此处输入图像描述


推荐阅读