使用身份在 Blazor 中检索用户名

Posted

技术标签:

【中文标题】使用身份在 Blazor 中检索用户名【英文标题】:Retrieving user name in Blazor using Identity 【发布时间】:2021-02-21 06:14:16 【问题描述】:

我有一个使用脚手架身份页面的 Blazor 应用程序。开箱即用,用户 ID 由 LoginDisplay.razor 组件显示。该组件调用

 @context.User.Identity.Name

显示当前用户标识(不是自然名称)。 因此,为了显示自然名称,我使用本指南首先在默认身份架构中进行更改:https://docs.microsoft.com/en-us/aspnet/core/security/authentication/add-user-data?view=aspnetcore-3.1&tabs=visual-studio#test-create-view-download-delete-custom-user-data,因为 Blazor 脚手架身份使用剃刀页面。 但是,在这样做之后,我意识到无法在 Blazor 的 Razor 组件中获取这些额外的用户信息。但是,我发现声明可用于 Razor 组件。所以我想在用户注册时向他们添加声明。所以我用下面的语句在Register.cshtml.cs中添加了一个用户声明:

   await _userManager.AddClaimAsync(user, new System.Security.Claims.Claim("name", user.Name));

user.Name 来自用户输入。

这样做之后,有趣的部分是现在当我运行应用程序时,@context.User.Identity.Name 返回的是自然名称,而不是用户 ID。

我的问题是为什么会这样?为什么添加“名称”声明会使 @context.User.Identity.Name 返回自然名称,而不是像以前那样返回用户 ID?

我正在使用 .NET5 最新预览版。

完全糊涂了。

【问题讨论】:

浏览代码回答问题:github.com/dotnet/aspnetcore/blob/… 【参考方案1】:
await _userManager.AddClaimAsync(user, new System.Security.Claims.Claim("name", user.Name));

这样做不是一个好主意,除非你知道自己在做什么。

为什么添加“名称”声明会使 @context.User.Identity.Name 返回自然名称,而不是像以前那样返回用户 ID?

`@context.User.Identity.Name` ordinarily returns the value of `UserName` column in the Users table, which by default is the user's email. This value is passed to the client in the Jwt token as a claim called "name". If you add a user 

对于名为“name”且值为“NaturalName”的声明,Jwt 令牌将包含名为“name”且值为“NaturalName”的声明,而不是 UserName 专栏。这正是您的代码正在做的事情:将用户添加到 UserClaims 表中的“名称”声明中,因此 @context.User.Identity.Name 返回“自然名称”值。

顺便说一句,还有另一个名为 preferred_username 的声明仍然保留了 UserName 列的值;也就是email值...

但是,在这样做之后,我意识到无法在 Blazor 的 Razor 组件中获取这些额外的用户信息。

不是真的...我知道有五种方法可以做到这一点,具体取决于您的要求以及您使用的 Blazor 的风格。它是客户端还是服务器端?你没有提到这个...

是否记录了输入“名称”声明会强制 context.User.Identity.Name 提供“名称”声明而不是用户 ID 的任何地方?

我不知道……尤其不是你描述的方式。事情要复杂得多。实际上,它记录在我的回答中。文档没有太大的价值。你应该测试软件,了解它是如何工作的,等等。

告诉您该怎么做...在未将您的用户添加到任何声明的情况下运行您的应用程序。现在已通过身份验证,并看到您的电子邮件已显示。按 F12,导航到应用程序选项卡。查找键/值表下方的profile 部分,然后查找项目name。它的价值应该是您的电子邮件。 name 是声明的名称。这是name 声明。默认情况下,它由 IdentityServer 在 Jwt 令牌中传递,如果没有将 name 声明分配给用户,则其值取自 UserName 列。另请注意,还有另一个名为 preferred_username 的声明,其值是用户的电子邮件。

现在在 AspNetUserClaims 中为用户分配一个名为 name 的声明: 在 ClaimType 列中添加字符串 name,并在 ClaimValue 中设置字符串 user3656651...保存。现在再次运行您的应用程序,进行身份验证...@context.User.Identity.Name 现在显示字符串 user3656651,而不是用户的电子邮件,因为 IdentityServer 发现您的用户被分配了一个 name 声明,这对她来说更自然而不是显示自然名称;)。执行上述操作,您将学到比任何文档都多的东西。

注意:在您的 WebAssembly 应用程序的 Program.Main 方法中有以下代码:

builder.Services.AddApiAuthorization();

您可以将其扩充为 ;

builder.Services.AddApiAuthorization(configure => configure.UserOptions.NameClaim = "preferred_username");

获取或设置用于用户名的声明类型。

换句话说,@context.User.Identity.Name 被指示显示preferred_username 声明所持有的值。

注意:该指令是 Blazor 的一部分...preferred_username 声明由 IdentityServer 创建,由 OpenID Connect 和 oauth2.o 规范指定。

我知道的关于上述指令的唯一文档是:获取或 设置用于用户名的声明类型。并且在发现上面的选项后发现了...

无论如何,这是什么意思?默认情况下使用name 声明...

【讨论】:

我正在使用 blazor wasm。 OK...你还在困惑吗?你已经得到了答案...... 是否记录了输入“名称”声明会强制 context.User.Identity.Name 提供“名称”声明而不是用户 ID 的任何地方?如果是这种情况,那么我的代码必须是正确的并且它符合预期。如果不是,那么为什么 context.User.Identity.Name 返回不同的值? 我已经添加了对答案的回复。 好的,这是一些很棒的信息。因此,根据您的评论,如果存在声明,则使用它,否则使用 UserName 列(其中包含电子邮件 ID)。因此,只要我对每个注册用户都有一个名称声明,我应该可以使用此代码。伟大的!谢谢!

以上是关于使用身份在 Blazor 中检索用户名的主要内容,如果未能解决你的问题,请参考以下文章

如何在服务器端 Blazor 中使用 HttpContext 对象来检索有关用户、用户代理的信息

在 Blazor 中的视图之外访问经过身份验证的用户

从 Blazor 应用中的中间件类获取经过身份验证的用户

如何使用 Blazor Server 对用户进行身份验证

当用户在 Blazor Webassembly 身份验证和授权中具有多个角色时出现问题?

如何在 blazor webassembly 项目中对服务器端控制器中的用户进行身份验证?