每页上的ASP.NET MVC自定义用户字段

时间:2015-08-26 21:58:56

标签: asp.net asp.net-mvc razor asp.net-identity-2

背景 我正在构建越来越多的Web应用程序,设计师/模板制作者决定添加一个"个人资料图片"以及其他一些与用户相关的数据,当然只有在有人登录时才会使用。

正如大多数ASP.NET MVC开发人员一样,我使用viewmodels为razor布局提供我需要显示的信息,这些信息源自存储库等。

使用

显示用户名很容易
HttpContext.Current.User.Identity.Name

如果我想在这些页面上显示保存在我的后备数据存储区中的信息,该怎么办? ApplicationUser类中的自定义字段,如业务单位名称或个人资料图片CDN网址。

(为了简单起见,我们假设我将Identity Framework与包含我的ApplicationUsers的实体框架(SQL数据库)一起使用)

问题

你如何解决这个问题:

  1. 不用polval viewmodel / controller树(例如构建一个BaseViewModel或BaseController填充/提供这些信息?
  2. 无需为每个页面请求往返数据库这些详细信息?
  3. 如果用户未登录,则不查询数据库?
  4. 当您无法使用SESSION数据时(因为我的应用程序通常在多个Azure实例上扩展 - read why this isn't possible here) - 我对SQL缓存或Redis缓存不感兴趣。
  5. 我已经考虑过使用部署新的自己的viewmodel - 但是仍然会在每个页面加载时往返于SQL数据库。会话数据现在是安全的,但是当用azure放大时,这也不是一种方法。知道什么是我最好的选择吗?

    TLDR;

    如果用户已登录(我访问=允许),我想在我的应用程序的每个页面上显示用户配置文件信息(ApplicationUser)。如何在不查询每个页面请求的数据库的情况下显示此信息?如果没有Session类,我该怎么做?如何在不构建基类的情况下执行此操作?

1 个答案:

答案 0 :(得分:4)

Identity的最佳方式是使用声明存储有关用户的自定义数据。 Sam的答案与我在这里所说的非常接近。我会详细说明一下。

ApplicationUser课程中,您拥有用于创建用户GenerateUserIdentityAsync的{​​{1}}方法:

ClaimsIdentity

这会在用户身份上添加键值对,最终在身份验证cookie中进行序列化和加密 - 这一点很重要。

用户登录后,public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser, string> 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.AddClaims(new[] { new Claim("MyApp:FirstName",this.FirstName), //presuming FirstName is part of ApplicationUser class new Claim("MyApp:LastName",this.LastName), }); return userIdentity; } 可以使用此标识 - 该对象实际上是HttpContext.Current.User.Identity,其中包含从Cookie中获取的声明。因此,无论您在登录时间提出索赔,都可以随时使用,而无需深入了解数据库。

要从索赔中获取数据,我通常会在ClaimsIdentity

上执行扩展方法
IPrincipal

这样您就可以从Razor视图访问您的声明数据:public static String GetFirstName(this IPrincipal principal) { var claimsPrincipal = principal as ClaimsPrincipal; if (claimsPrincipal == null) { throw new DomainException("User is not authenticated"); } var personNameClaim = claimsPrincipal.Claims.FirstOrDefault(c => c.Type == "MyApp:FirstName"); if (personNameClaim != null) { return personNameClaim.Value; } return String.Empty; }

此操作非常快,因为它不需要DI容器中的任何对象解析,也不会查询数据库。

唯一的障碍是当存储中的值实际更新时,auth cookie中的声明中的值在用户注销和登录之前不会刷新。但您可以通过User.GetFirstName()自行强制执行此操作,并立即使用更新的声明值重新签名。