Tim*_*ong 19 c# asp.net-core asp.net-core-identity
我正在开发一个ASP.Net vNext/MVC6项目.我正在掌握ASP.Net Identity.
本ApplicationUser类显然是在那里我应该添加任何额外的用户属性,这可与实体框架和我的附加属性获取存储在数据库中的预期.
但是,当我想从我的视图中访问当前登录用户的详细信息时,问题就出现了.具体来说,我有一个_loginPartial.cshtml我想要检索并显示用户的Gravatar图标,我需要该电子邮件地址.
Razor View基类有一个User属性,它是一个ClaimsPrincipal.如何从此User属性返回到我的ApplicationUser,以检索我的自定义属性?
请注意,我不是在询问如何查找信息; 我知道如何ApplicationUser从User.GetUserId()值中查找.这是一个关于如何合理地解决这个问题的问题.具体来说,我不想:
这似乎是一个"横切关注点",应该有一个集中的标准解决方案,但我觉得我错过了一块拼图游戏.从视图中获取这些自定义用户属性的最佳方法是什么?
注意:似乎MVC团队通过确保UserName属性始终设置为用户的电子邮件地址,在项目模板中侧面解决了这个问题,巧妙地避免了他们执行此查找以获取用户的电子邮件地址!这对我来说似乎有点欺骗,在我的解决方案中,用户的登录名可能是也可能不是他们的电子邮件地址,所以我不能依赖这个技巧(我怀疑还有其他属性我需要稍后访问).
Alf*_*fer 15
我认为您应该为此目的使用User的Claims属性.我找到了很好的帖子:http://benfoster.io/blog/customising-claims-transformation-in-aspnet-core-identity
用户类
public class ApplicationUser : IdentityUser
{
public string MyProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我们将MyProperty放入经过身份验证的用户声明中.为此,我们重写了UserClaimsPrincipalFactory
public class MyUserClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>
{
public MyUserClaimsPrincipalFactory (
UserManager<ApplicationUser> userManager,
RoleManager<IdentityRole> roleManager,
IOptions<IdentityOptions> optionsAccessor) : base(userManager, roleManager, optionsAccessor)
{
}
public async override Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
{
var principal = await base.CreateAsync(user);
//Putting our Property to Claims
//I'm using ClaimType.Email, but you may use any other or your own
((ClaimsIdentity)principal.Identity).AddClaims(new[] {
new Claim(ClaimTypes.Email, user.MyProperty)
});
return principal;
}
}
Run Code Online (Sandbox Code Playgroud)
在Startup.cs中注册我们的UserClaimsPrincipalFactory
public void ConfigureServices(IServiceCollection services)
{
//...
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, MyUserClaimsPrincipalFactory>();
//...
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以像这样访问我们的主题
User.Claims.FirstOrDefault(v => v.Type == ClaimTypes.Email).Value;
Run Code Online (Sandbox Code Playgroud)
我们可以创建一个扩展
namespace MyProject.MyExtensions
{
public static class MyUserPrincipalExtension
{
public static string MyProperty(this ClaimsPrincipal user)
{
if (user.Identity.IsAuthenticated)
{
return user.Claims.FirstOrDefault(v => v.Type == ClaimTypes.Email).Value;
}
return "";
}
}
}
Run Code Online (Sandbox Code Playgroud)
我们应该将@Using添加到View(我将它添加到全局_ViewImport.cshtml)
@using MyProject.MyExtensions
Run Code Online (Sandbox Code Playgroud)
最后,我们可以在任何View中使用此属性作为方法调用
@User.MyProperty()
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您没有额外的数据库查询来获取用户信息.
wil*_*han 15
更新到原始答案:(这违反了操作系统的第一个要求,如果您有相同的要求,请参阅我的原始答案)您可以通过在Razor视图中引用FullName来修改声明并添加扩展文件(在我的原始解决方案中)如:
@UserManager.GetUserAsync(User).Result.FullName
Run Code Online (Sandbox Code Playgroud)
原答案:
这只是这个stackoverflow问题的一个较短的例子,并且在本教程之后.
假设您已经在"ApplicationUser.cs"中设置了属性以及适用的ViewModel和Views进行注册.
使用"FullName"作为额外属性的示例:
将"AccountController.cs"注册方法修改为:
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var user = new ApplicationUser {
UserName = model.Email,
Email = model.Email,
FullName = model.FullName //<-ADDED PROPERTY HERE!!!
};
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
//ADD CLAIM HERE!!!!
await _userManager.AddClaimAsync(user, new Claim("FullName", user.FullName));
await _signInManager.SignInAsync(user, isPersistent: false);
_logger.LogInformation(3, "User created a new account with password.");
return RedirectToLocal(returnUrl);
}
AddErrors(result);
}
return View(model);
}
Run Code Online (Sandbox Code Playgroud)
然后我添加了一个新文件"Extensions/ClaimsPrincipalExtension.cs"
using System.Linq;
using System.Security.Claims;
namespace MyProject.Extensions
{
public static class ClaimsPrincipalExtension
{
public static string GetFullName(this ClaimsPrincipal principal)
{
var fullName = principal.Claims.FirstOrDefault(c => c.Type == "FullName");
return fullName?.Value;
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后在您查看您需要访问属性的位置添加:
@using MyProject.Extensions
Run Code Online (Sandbox Code Playgroud)
并在需要时通过以下方式调用:
@User.GetFullName()
Run Code Online (Sandbox Code Playgroud)
这样做的一个问题是我必须删除我当前的测试用户,然后重新注册,以便查看"FullName",即使数据库中有FullName属性.
您需要使用当前用户的名称进行搜索(例如使用实体框架):
HttpContext.Current.User.Identity.Name
Run Code Online (Sandbox Code Playgroud)