asp.net-mvc 如何扩展 User.Identity 的可用属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28335353/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to extend available properties of User.Identity
提问by RobHurd
I'm using MVC5 Identity 2.0 for users to log into my website, where the authentication details are stored in an SQL database. Asp.net Identity has been implemented in a standard way as can be found in many online tutorials.
我正在使用 MVC5 Identity 2.0 供用户登录我的网站,其中身份验证详细信息存储在 SQL 数据库中。Asp.net Identity 已经以标准方式实现,可以在许多在线教程中找到。
The ApplicationUser class in IdentityModels has been extended to include some custom properties, such as an integer OrganizationId. The idea is that many users can be created and assigned to a common Organization for database relationship purposes.
IdentityModels 中的 ApplicationUser 类已扩展为包括一些自定义属性,例如整数 OrganizationId。这个想法是为了数据库关系的目的,可以创建许多用户并将其分配给一个公共组织。
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
//Extended Properties
public DateTime? BirthDate { get; set; }
public long? OrganizationId { get; set; }
//Key Mappings
[ForeignKey("OrganizationId")]
public virtual Organization Organization { get; set; }
}
How can I retrieve the OrganizationId property of the currently logged in user from within a controller? Is this available via a method once a user is logged in or do I always have the retrieve the OrganizationId from the database, based on the UserId, every time a controller method executes?
如何从控制器中检索当前登录用户的 OrganizationId 属性?一旦用户登录,这是否可以通过方法获得,或者每次执行控制器方法时,我是否总是根据 UserId 从数据库中检索 OrganizationId?
Reading around on the web I have seen I need to use the following to get the logged in UserId etc.
在网上阅读我看到我需要使用以下内容来获取登录的 UserId 等。
using Microsoft.AspNet.Identity;
...
User.Identity.GetUserId();
However, OrganizationId is not a property available in User.Identity. Do I need to extend User.Identity to include the OrganizationId property? If so, how do I go about this.
但是,OrganizationId 不是 User.Identity 中可用的属性。我是否需要扩展 User.Identity 以包含 OrganizationId 属性?如果是这样,我该怎么做。
The reason I need the OrganizationId so often is that many table queries are reliant on the OrganizationId to retrieve data relevant to the Organization that's associated to the logged in user.
我经常需要 OrganizationId 的原因是许多表查询依赖于 OrganizationId 来检索与登录用户关联的组织相关的数据。
回答by Pawel
Whenever you want to extend the properties of User.Identity with any additional properties like the question above, add these properties to the ApplicationUser class first like so:
每当您想使用任何其他属性(如上述问题)扩展 User.Identity 的属性时,首先将这些属性添加到 ApplicationUser 类中,如下所示:
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
// Your Extended Properties
public long? OrganizationId { get; set; }
}
Then what you need is to create an extension method like so (I create mine in an new Extensions folder):
然后你需要创建一个像这样的扩展方法(我在一个新的扩展文件夹中创建我的):
namespace App.Extensions
{
public static class IdentityExtensions
{
public static string GetOrganizationId(this IIdentity identity)
{
var claim = ((ClaimsIdentity)identity).FindFirst("OrganizationId");
// Test for null to avoid issues during local testing
return (claim != null) ? claim.Value : string.Empty;
}
}
}
When you create the Identity in the ApplicationUser class, just add the Claim -> OrganizationId like so:
在 ApplicationUser 类中创建 Identity 时,只需添加 Claim -> OrganizationId ,如下所示:
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here => this.OrganizationId is a value stored in database against the user
userIdentity.AddClaim(new Claim("OrganizationId", this.OrganizationId.ToString()));
return userIdentity;
}
Once you added the claim and have your extension method in place, to make it available as a property on your User.Identity, add a using statement on the page/file you want to access it:
添加声明并准备好扩展方法后,要使其作为 User.Identity 的属性可用,请在要访问它的页面/文件上添加 using 语句:
in my case: using App.Extensions;within a Controller and @using. App.Extensionswithing a .cshtml View file.
就我而言:using App.Extensions;在控制器中并@using. App.Extensions带有 .cshtml 视图文件。
EDIT:
编辑:
What you can also do to avoid adding a using statement in every View is to go to the Views folder, and locate the Web.config file in there.
Now look for the <namespaces>tag and add your extension namespace there like so:
为了避免在每个视图中添加 using 语句,您还可以转到 Views 文件夹,并在其中找到 Web.config 文件。现在查找<namespaces>标签并在那里添加您的扩展命名空间,如下所示:
<add namespace="App.Extensions" />
Save your file and you're done. Now every View will know of your extensions.
保存你的文件,你就完成了。现在每个视图都会知道您的扩展。
You can access the Extension Method:
您可以访问扩展方法:
var orgId = User.Identity.GetOrganizationId();
回答by AxleWack
I was looking for the same solution and Pawel gave me 99% of the answer. The only thing that was missing that I needed for the Extension to display was adding the following Razor Code into the cshtml(view) page:
我一直在寻找相同的解决方案,Pawel 给了我 99% 的答案。显示扩展所需的唯一缺少的是将以下 Razor 代码添加到 cshtml(view) 页面中:
@using programname.Models.Extensions
@using programname.Models.Extensions
I was looking for the FirstName, to display in the top right of my NavBar after the user logged in.
我正在寻找名字,在用户登录后显示在我的导航栏的右上角。
I thought I would post this incase it helps someone else, So here is my code:
我想我会发布这个,以防它对其他人有帮助,所以这是我的代码:
I created a new folder called Extensions(Under my Models Folder) and created the new class as Pawel specified above: IdentityExtensions.cs
我创建了一个名为 Extensions(在我的模型文件夹下)的新文件夹,并创建了上面指定的 Pawel 的新类: IdentityExtensions.cs
using System.Security.Claims;
using System.Security.Principal;
namespace ProgramName.Models.Extensions
{
public static class IdentityExtensions
{
public static string GetUserFirstname(this IIdentity identity)
{
var claim = ((ClaimsIdentity)identity).FindFirst("FirstName");
// Test for null to avoid issues during local testing
return (claim != null) ? claim.Value : string.Empty;
}
}
}
IdentityModels.cs:
IdentityModels.cs:
public class ApplicationUser : IdentityUser
{
//Extended Properties
public string FirstName { get; internal set; }
public string Surname { get; internal set; }
public bool isAuthorized { get; set; }
public bool isActive { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
userIdentity.AddClaim(new Claim("FirstName", this.FirstName));
return userIdentity;
}
}
Then in my _LoginPartial.cshtml(Under Views/SharedFolders) I added @using.ProgramName.Models.Extensions
然后在我的_LoginPartial.cshtml(在Views/Shared文件夹下)我添加了@using.ProgramName.Models.Extensions
I then added the change to the folling line of code that was going to use the Users First name after Logging in :
然后,我将更改添加到将在登录后使用用户名的以下代码行:
@Html.ActionLink("Hello " + User.Identity.GetUserFirstname() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
@Html.ActionLink("Hello " + User.Identity.GetUserFirstname() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
Perhaps this helps someone else down the line.
也许这可以帮助其他人。
回答by Dhaust
Check out this great blog post by John Atten: ASP.NET Identity 2.0: Customizing Users and Roles
查看 John Atten 的这篇精彩博文: ASP.NET Identity 2.0:自定义用户和角色
It has great step-by-step info on the whole process. Go read it : )
它对整个过程有很好的分步信息。去读吧:)
Here are some of the basics.
以下是一些基础知识。
Extend the default ApplicationUser class by adding new properties (i.e.- Address, City, State, etc.):
通过添加新属性(即地址、城市、州等)来扩展默认的 ApplicationUser 类:
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity>
GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
}
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
// Use a sensible display name for views:
[Display(Name = "Postal Code")]
public string PostalCode { get; set; }
// Concatenate the address info for display in tables and such:
public string DisplayAddress
{
get
{
string dspAddress = string.IsNullOrWhiteSpace(this.Address) ? "" : this.Address;
string dspCity = string.IsNullOrWhiteSpace(this.City) ? "" : this.City;
string dspState = string.IsNullOrWhiteSpace(this.State) ? "" : this.State;
string dspPostalCode = string.IsNullOrWhiteSpace(this.PostalCode) ? "" : this.PostalCode;
return string.Format("{0} {1} {2} {3}", dspAddress, dspCity, dspState, dspPostalCode);
}
}
Then you add your new properties to your RegisterViewModel.
然后将新属性添加到 RegisterViewModel。
// Add the new address properties:
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
Then update the Register View to include the new properties.
然后更新注册视图以包含新属性。
<div class="form-group">
@Html.LabelFor(m => m.Address, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.Address, new { @class = "form-control" })
</div>
</div>
Then update the Register() method on AccountController with the new properties.
然后使用新属性更新 AccountController 上的 Register() 方法。
// Add the Address properties:
user.Address = model.Address;
user.City = model.City;
user.State = model.State;
user.PostalCode = model.PostalCode;
回答by Jashan
For anyone that finds this question looking for how to access custom properties in ASP.NET Core 2.1 - it's much easier: You'll have a UserManager, e.g. in _LoginPartial.cshtml, and then you can simply do (assuming "ScreenName" is a property that you have added to your own AppUser which inherits from IdentityUser):
对于在 ASP.NET Core 2.1 中查找如何访问自定义属性的任何发现此问题的人 - 这要容易得多:您将有一个 UserManager,例如在 _LoginPartial.cshtml 中,然后您可以简单地做(假设“ScreenName”是一个您已添加到您自己的 AppUser 的属性,该属性继承自 IdentityUser):
@using Microsoft.AspNetCore.Identity
@using <namespaceWhereYouHaveYourAppUser>
@inject SignInManager<AppUser> SignInManager
@inject UserManager<AppUser> UserManager
@if (SignInManager.IsSignedIn(User)) {
<form asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="@Url.Action("Index", "Home", new { area = "" })"
method="post" id="logoutForm"
class="form-inline my-2 my-lg-0">
<ul class="nav navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">
Hello @((await UserManager.GetUserAsync(User)).ScreenName)!
<!-- Original code, shows Email-Address: @UserManager.GetUserName(User)! -->
</a>
</li>
<li class="nav-item">
<button type="submit" class="btn btn-link nav-item navbar-link nav-link">Logout</button>
</li>
</ul>
</form>
} else {
<ul class="navbar-nav ml-auto">
<li class="nav-item"><a class="nav-link" asp-area="Identity" asp-page="/Account/Register">Register</a></li>
<li class="nav-item"><a class="nav-link" asp-area="Identity" asp-page="/Account/Login">Login</a></li>
</ul>
}
回答by codeMethod
Dhaust gives a good way to add the property to the ApplicationUser class. Looking at the OP code it appears they may have done this or were on track to do that. The question asks
Dhaust 提供了一种将属性添加到 ApplicationUser 类的好方法。查看 OP 代码,似乎他们可能已经这样做了或者正在这样做。问题问
How can I retrieve the OrganizationId property of the currently logged in user from within a controller? However, OrganizationId is not a property available in User.Identity. Do I need to extend User.Identity to include the OrganizationId property?
如何从控制器中检索当前登录用户的 OrganizationId 属性?但是,OrganizationId 不是 User.Identity 中可用的属性。我是否需要扩展 User.Identity 以包含 OrganizationId 属性?
Pawel gives a way to add an extension method that requires using statements or adding the namespace to the web.config file.
Pawel 提供了一种添加扩展方法的方法,该方法需要 using 语句或将命名空间添加到 web.config 文件。
However, the question asks if you "need to" extend User.Identity to include the new property. There is an alternative way to access the property without extending User.Identity. If you followed Dhaust method you can then use the following code in your controller to access the new property.
但是,问题会询问您是否“需要”扩展 User.Identity 以包含新属性。有一种替代方法可以在不扩展 User.Identity 的情况下访问该属性。如果您遵循 Dhaust 方法,则可以在控制器中使用以下代码来访问新属性。
ApplicationDbContext db = new ApplicationDbContext();
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
var currentUser = manager.FindById(User.Identity.GetUserId());
var myNewProperty = currentUser.OrganizationId;
回答by Anthony Griggs
I also had added on or extended additional columns into my AspNetUsers table. When I wanted to simply view this data I found many examples like the code above with "Extensions" etc... This really amazed me that you had to write all those lines of code just to get a couple values from the current users.
我还在 AspNetUsers 表中添加或扩展了其他列。当我想简单地查看这些数据时,我发现了许多示例,例如上面带有“扩展”等的代码……这让我感到非常惊讶,您必须编写所有这些代码行才能从当前用户那里获取一些值。
It turns out that you can query the AspNetUsers table like any other table:
事实证明,您可以像查询任何其他表一样查询 AspNetUsers 表:
ApplicationDbContext db = new ApplicationDbContext();
var user = db.Users.Where(x => x.UserName == User.Identity.Name).FirstOrDefault();

