如何扩展 User.Identity 的可用属性
How to extend available properties of User.Identity
我正在使用 MVC5 Identity 2.0 供用户登录我的网站,身份验证详细信息存储在 SQL 数据库中。 Asp.net Identity 已经以标准方式实现,可以在许多在线教程中找到。
IdentityModels 中的 ApplicationUser class 已扩展为包含一些自定义属性,例如整数 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; }
}
如何从控制器中检索当前登录用户的 OrganizationId 属性?
这是在用户登录后通过方法提供的,还是每次控制器方法执行时,我总是根据 UserId 从数据库中检索 OrganizationId?
在网上阅读我发现我需要使用以下方法来获取登录的 UserId 等。
using Microsoft.AspNet.Identity;
...
User.Identity.GetUserId();
但是,OrganizationId 在 User.Identity 中不可用 属性。我是否需要扩展 User.Identity 以包含 OrganizationId 属性?如果是这样,我该怎么做。
我经常需要 OrganizationId 的原因是许多 table 查询依赖于 OrganizationId 来检索与登录用户关联的组织相关的数据。
查看 John Atten 的精彩博客 post:
ASP.NET Identity 2.0: Customizing Users and Roles
它包含有关整个过程的详细分步信息。去读吧:)
这是一些基础知识。
通过添加新属性(即地址、城市、州等)扩展默认的 ApplicationUser class:
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);
}
}
然后将新属性添加到 RegisterViewModel。
// Add the new address properties:
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
然后更新注册视图以包含新属性。
<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>
然后使用新属性更新 AccountController 上的 Register() 方法。
// Add the Address properties:
user.Address = model.Address;
user.City = model.City;
user.State = model.State;
user.PostalCode = model.PostalCode;
每当您想使用任何其他属性(如上述问题)扩展 User.Identity 的属性时,首先将这些属性添加到 ApplicationUser class,如下所示:
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; }
}
然后你需要像这样创建一个扩展方法(我在一个新的扩展文件夹中创建我的):
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;
}
}
}
当您在 ApplicationUser class 中创建身份时,只需像这样添加 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;
}
添加声明并准备好扩展方法后,要使其在 User.Identity 上作为 属性 可用,在 [=] 上添加 using 语句38=] 你想访问它:
在我的例子中:using App.Extensions;
在控制器中,@using. App.Extensions
使用 .cshtml 视图文件。
编辑:
为了避免在每个视图中添加 using 语句,您还可以转到 Views 文件夹,然后在其中找到 Web.config 文件。
现在寻找 <namespaces>
标签并在其中添加您的扩展名称空间,如下所示:
<add namespace="App.Extensions" />
保存文件,大功告成。现在每个视图都会知道您的扩展。
您可以访问扩展方法:
var orgId = User.Identity.GetOrganizationId();
我一直在寻找相同的解决方案,Pawel 给了我 99% 的答案。显示扩展所需的唯一缺失是将以下 Razor 代码添加到 cshtml(view) 页面中:
@using programname.Models.Extensions
我正在寻找名字,以便在用户登录后显示在我的导航栏的右上角。
我想我会 post 以防对其他人有帮助,所以这是我的代码:
我创建了一个名为 Extensions 的新文件夹(在我的模型文件夹下)并创建了新的 class 作为上面指定的 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
:
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;
}
}
然后在我的 _LoginPartial.cshtml
(在 Views/Shared
文件夹下)我添加了 @using.ProgramName.Models.Extensions
然后我将更改添加到将在登录后使用用户名字的以下代码行:
@Html.ActionLink("Hello " + User.Identity.GetUserFirstname() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
也许这对其他人有帮助。
Dhaust 提供了一种将 属性 添加到 ApplicationUser class 的好方法。查看 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?
Pawel 提供了一种添加扩展方法的方法,该扩展方法需要使用语句或将命名空间添加到 web.config 文件。
但是,问题是询问您是否 "need to" 扩展 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;
我还在我的 AspNetUsers table 中添加或扩展了额外的列。当我想简单地查看这些数据时,我发现了很多例子,比如上面的代码 "Extensions" 等......这让我感到非常惊讶,你不得不编写所有这些代码行只是为了从当前用户那里获取几个值.
事实证明,您可以像查询其他查询一样查询 AspNetUsers table table:
ApplicationDbContext db = new ApplicationDbContext();
var user = db.Users.Where(x => x.UserName == User.Identity.Name).FirstOrDefault();
对于任何发现此问题并正在寻找如何访问 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>
}
我正在使用 MVC5 Identity 2.0 供用户登录我的网站,身份验证详细信息存储在 SQL 数据库中。 Asp.net Identity 已经以标准方式实现,可以在许多在线教程中找到。
IdentityModels 中的 ApplicationUser class 已扩展为包含一些自定义属性,例如整数 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; }
}
如何从控制器中检索当前登录用户的 OrganizationId 属性? 这是在用户登录后通过方法提供的,还是每次控制器方法执行时,我总是根据 UserId 从数据库中检索 OrganizationId?
在网上阅读我发现我需要使用以下方法来获取登录的 UserId 等。
using Microsoft.AspNet.Identity;
...
User.Identity.GetUserId();
但是,OrganizationId 在 User.Identity 中不可用 属性。我是否需要扩展 User.Identity 以包含 OrganizationId 属性?如果是这样,我该怎么做。
我经常需要 OrganizationId 的原因是许多 table 查询依赖于 OrganizationId 来检索与登录用户关联的组织相关的数据。
查看 John Atten 的精彩博客 post: ASP.NET Identity 2.0: Customizing Users and Roles
它包含有关整个过程的详细分步信息。去读吧:)
这是一些基础知识。
通过添加新属性(即地址、城市、州等)扩展默认的 ApplicationUser class:
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);
}
}
然后将新属性添加到 RegisterViewModel。
// Add the new address properties:
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
然后更新注册视图以包含新属性。
<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>
然后使用新属性更新 AccountController 上的 Register() 方法。
// Add the Address properties:
user.Address = model.Address;
user.City = model.City;
user.State = model.State;
user.PostalCode = model.PostalCode;
每当您想使用任何其他属性(如上述问题)扩展 User.Identity 的属性时,首先将这些属性添加到 ApplicationUser class,如下所示:
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; }
}
然后你需要像这样创建一个扩展方法(我在一个新的扩展文件夹中创建我的):
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;
}
}
}
当您在 ApplicationUser class 中创建身份时,只需像这样添加 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;
}
添加声明并准备好扩展方法后,要使其在 User.Identity 上作为 属性 可用,在 [=] 上添加 using 语句38=] 你想访问它:
在我的例子中:using App.Extensions;
在控制器中,@using. App.Extensions
使用 .cshtml 视图文件。
编辑:
为了避免在每个视图中添加 using 语句,您还可以转到 Views 文件夹,然后在其中找到 Web.config 文件。
现在寻找 <namespaces>
标签并在其中添加您的扩展名称空间,如下所示:
<add namespace="App.Extensions" />
保存文件,大功告成。现在每个视图都会知道您的扩展。
您可以访问扩展方法:
var orgId = User.Identity.GetOrganizationId();
我一直在寻找相同的解决方案,Pawel 给了我 99% 的答案。显示扩展所需的唯一缺失是将以下 Razor 代码添加到 cshtml(view) 页面中:
@using programname.Models.Extensions
我正在寻找名字,以便在用户登录后显示在我的导航栏的右上角。
我想我会 post 以防对其他人有帮助,所以这是我的代码:
我创建了一个名为 Extensions 的新文件夹(在我的模型文件夹下)并创建了新的 class 作为上面指定的 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
:
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;
}
}
然后在我的 _LoginPartial.cshtml
(在 Views/Shared
文件夹下)我添加了 @using.ProgramName.Models.Extensions
然后我将更改添加到将在登录后使用用户名字的以下代码行:
@Html.ActionLink("Hello " + User.Identity.GetUserFirstname() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
也许这对其他人有帮助。
Dhaust 提供了一种将 属性 添加到 ApplicationUser class 的好方法。查看 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?
Pawel 提供了一种添加扩展方法的方法,该扩展方法需要使用语句或将命名空间添加到 web.config 文件。
但是,问题是询问您是否 "need to" 扩展 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;
我还在我的 AspNetUsers table 中添加或扩展了额外的列。当我想简单地查看这些数据时,我发现了很多例子,比如上面的代码 "Extensions" 等......这让我感到非常惊讶,你不得不编写所有这些代码行只是为了从当前用户那里获取几个值.
事实证明,您可以像查询其他查询一样查询 AspNetUsers table table:
ApplicationDbContext db = new ApplicationDbContext();
var user = db.Users.Where(x => x.UserName == User.Identity.Name).FirstOrDefault();
对于任何发现此问题并正在寻找如何访问 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>
}