如何扩展 User.Identity 的可用属性

我正在使用 MVC5 Identity 2.0让用户登录我的网站,其中的身份验证详细信息存储在一个 SQL 数据库中。Net Identity 已经以一种标准的方式实现,这可以在许多在线教程中找到。

IdentityModel 中的 ApplicationUser 类已经扩展为包含一些自定义属性,例如整数 Organization ationId。其思想是,出于数据库关系的目的,可以创建许多用户并将其分配给公共组织。

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

如何从控制器中检索当前登录用户的 OrganationId 属性? 一旦用户登录,这是否可以通过一个方法获得,还是每次执行控制器方法时,我都可以根据 UserId 从数据库中检索 OrganationId?

在网上浏览时,我发现我需要使用以下命令来登录 UserId 等等。

using Microsoft.AspNet.Identity;
...
User.Identity.GetUserId();

但是,Organization ationId 不是 User 中可用的属性。身份。我是否需要扩展用户。包含 Organization-Id 属性的身份?如果是这样,我该怎么做。

我之所以经常需要 Organization ationId,是因为许多表查询都依赖于 Organization ationId 来检索与已登录用户相关的组织相关的数据。

122132 次浏览

看看 John Atten 写的这篇伟大的博文: NET Identity 2.0: 定制用户和角色

它对整个过程有很好的一步一步的信息。去阅读它:)

下面是一些基本的知识。

通过添加新属性(如-Address、 City、 State 等)扩展默认的 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);
}
}

然后将新属性添加到 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 的属性时。使用任何其他属性(如上面的问题)标识,首先将这些属性添加到 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; }
}

然后你需要创建一个像这样的扩展方法(我在一个新的扩展文件夹中创建我的扩展方法) :

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 类中创建 Identity 时,只需像下面这样添加 Claim-> Organization ationId:

    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 上将其作为属性使用。身份 在要访问的页面/文件上添加 using 语句:

在我的例子中: Controller 中的 using App.Extensions;和. cshtml 视图文件中的 @using. App.Extensions

编辑:

为了避免在每个 View 中添加 using 语句,还可以进入 View 文件夹,并在其中找到 Web.config 文件。 现在查找 <namespaces>标记并在其中添加扩展名称空间,如下所示:

<add namespace="App.Extensions" />

保存文件就可以了。现在每个视图都会知道你的扩展名。

您可以访问扩展方法:

var orgId = User.Identity.GetOrganizationId();

我也在寻找同样的解决方案帕维尔给了我99% 的答案。我需要扩展显示的唯一缺少的东西是在 cshtml (view)页面中添加以下 Razor Code:

@using programname.Models.Extensions

我正在寻找 FirstName,它将在用户登录后显示在我的 NavBar 的右上角。

我觉得我应该把这个贴出来,以防对别人有帮助,所以这是我的代码:

我创建了一个名为 Extended (在我的 ModelsFolder 下)的新文件夹,并按照上面指定的 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;
}
}
}

返回文章页面

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 类提供了一种很好的方法。看看 OP 代码,似乎他们可能已经这样做,或正在轨道上这样做。问题是

如何从控制器中检索当前登录用户的 OrganationId 属性?但是,Organization ationId 不是 User 中可用的属性。身份。我是否需要扩展用户。包含 Organization-Id 属性的身份?

Pawel 提供了一种添加扩展方法的方法,该方法需要使用语句或将名称空间添加到 web.config 文件中。

但是,这个问题询问您是否“需要”扩展 User。标识以包含新属性。还有一种不扩展 User 的访问属性的替代方法。身份。如果遵循 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 表中添加或扩展了其他列。当我想要简单地查看这些数据时,我发现了许多例子,比如上面的代码和“扩展”等等。.这真的让我感到惊讶,你必须编写所有这些代码行只是为了从当前用户那里得到一些值。

事实证明,您可以像查询其他表一样查询 AspNetUsers 表:

 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>
}