背景 我正在构建越来越多的Web应用程序,设计师/模板制作者决定添加一个"个人资料图片"以及其他一些与用户相关的数据,当然只有在有人登录时才会使用。
正如大多数ASP.NET MVC开发人员一样,我使用viewmodels为razor布局提供我需要显示的信息,这些信息源自存储库等。
使用
显示用户名很容易HttpContext.Current.User.Identity.Name
如果我想在这些页面上显示保存在我的后备数据存储区中的信息,该怎么办? ApplicationUser类中的自定义字段,如业务单位名称或个人资料图片CDN网址。
(为了简单起见,我们假设我将Identity Framework与包含我的ApplicationUsers的实体框架(SQL数据库)一起使用)
问题
你如何解决这个问题:
我已经考虑过使用部署新的自己的viewmodel - 但是仍然会在每个页面加载时往返于SQL数据库。会话数据现在是安全的,但是当用azure放大时,这也不是一种方法。知道什么是我最好的选择吗?
TLDR;
如果用户已登录(我访问=允许),我想在我的应用程序的每个页面上显示用户配置文件信息(ApplicationUser)。如何在不查询每个页面请求的数据库的情况下显示此信息?如果没有Session类,我该怎么做?如何在不构建基类的情况下执行此操作?
答案 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()
自行强制执行此操作,并立即使用更新的声明值重新签名。