Как я могу получить конкретные поля текущего зарегистрированного пользователя в MVC5?
У меня есть приложение MVC5, которое использует индивидуальную проверку подлинности и, конечно же, идентификатор ASP.NET. Дело в том, что я расширил модель, которая наследуется от ApplicationUser, она просто определяется следующим образом:
public class NormalUser : ApplicationUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Итак, дело в том, что, прежде всего, я хочу проверить, есть ли зарегистрированный пользователь, и если есть, я хочу получить его/ее поля FirstName, LastName и Email. Как я могу это достичь?
Я думаю, мне нужно использовать что-то вроде этого, чтобы проверить, есть ли зарегистрированный пользователь:
if (Request.IsAuthenticated)
{
...
}
Но как я могу получить значения этих конкретных полей для текущего пользователя?
Ответы
Ответ 1
Да, в Identity, если вам нужна дополнительная информация о пользователе, вы просто вытаскиваете пользователя из базы данных, так как теперь все это сохраняется на фактическом объекте пользователя.
if (Request.IsAuthenticated)
{
var user = UserManager.FindById(User.Identity.GetUserId());
}
Если GetUserId
не находится на User.Identity
, добавьте следующее к вашим сообщениям:
using Microsoft.AspNet.Identity;
Ответ 2
В MVC5 пользовательские данные сохраняются по умолчанию в сеансе, и по запросу данные анализируются в ClaimsPrincipal
, который содержит имя пользователя (или идентификатор) и формулы.
Именно так я и решил реализовать его, это может быть не простое решение, но это определенно упрощает его использование.
Пример использования:
В контроллере:
public ActionResult Index()
{
ViewBag.ReverseDisplayName = this.User.LastName + ", " + this.User.FirstName;
}
В поле зрения или _Layout:
@if(User.IsAuthenticated)
{
<span>@User.DisplayName</span>
}
1. Заменить ClaimsIdentityFactory
using System.Security.Claims;
using System.Threading.Tasks;
using Domain.Models;
using Microsoft.AspNet.Identity;
public class AppClaimsIdentityFactory : IClaimsIdentityFactory<User, int>
{
internal const string IdentityProviderClaimType = "http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider";
internal const string DefaultIdentityProviderClaimValue = "My Identity Provider";
/// <summary>
/// Constructor
/// </summary>
public AppClaimsIdentityFactory()
{
RoleClaimType = ClaimsIdentity.DefaultRoleClaimType;
UserIdClaimType = ClaimTypes.NameIdentifier;
UserNameClaimType = ClaimsIdentity.DefaultNameClaimType;
SecurityStampClaimType = Constants.DefaultSecurityStampClaimType;
}
/// <summary>
/// Claim type used for role claims
/// </summary>
public string RoleClaimType { get; set; }
/// <summary>
/// Claim type used for the user name
/// </summary>
public string UserNameClaimType { get; set; }
/// <summary>
/// Claim type used for the user id
/// </summary>
public string UserIdClaimType { get; set; }
/// <summary>
/// Claim type used for the user security stamp
/// </summary>
public string SecurityStampClaimType { get; set; }
/// <summary>
/// Create a ClaimsIdentity from a user
/// </summary>
/// <param name="manager"></param>
/// <param name="user"></param>
/// <param name="authenticationType"></param>
/// <returns></returns>
public virtual async Task<ClaimsIdentity> CreateAsync(UserManager<User, int> manager, User user, string authenticationType)
{
if (manager == null)
{
throw new ArgumentNullException("manager");
}
if (user == null)
{
throw new ArgumentNullException("user");
}
var id = new ClaimsIdentity(authenticationType, UserNameClaimType, RoleClaimType);
id.AddClaim(new Claim(UserIdClaimType, user.Id.ToString(), ClaimValueTypes.String));
id.AddClaim(new Claim(UserNameClaimType, user.UserName, ClaimValueTypes.String));
id.AddClaim(new Claim(IdentityProviderClaimType, DefaultIdentityProviderClaimValue, ClaimValueTypes.String));
id.AddClaim(new Claim(ClaimTypes.Email, user.EmailAddress));
if (user.ContactInfo.FirstName != null && user.ContactInfo.LastName != null)
{
id.AddClaim(new Claim(ClaimTypes.GivenName, user.ContactInfo.FirstName));
id.AddClaim(new Claim(ClaimTypes.Surname, user.ContactInfo.LastName));
}
if (manager.SupportsUserSecurityStamp)
{
id.AddClaim(new Claim(SecurityStampClaimType,
await manager.GetSecurityStampAsync(user.Id)));
}
if (manager.SupportsUserRole)
{
user.Roles.ToList().ForEach(r =>
id.AddClaim(new Claim(ClaimTypes.Role, r.Id.ToString(), ClaimValueTypes.String)));
}
if (manager.SupportsUserClaim)
{
id.AddClaims(await manager.GetClaimsAsync(user.Id));
}
return id;
}
2. Измените UserManager
, чтобы использовать его
public static UserManager<User,int> Create(IdentityFactoryOptions<AppUserManager> options, IOwinContext context)
{
var manager = new UserManager<User,int>(new UserStore<User,int>(new ApplicationDbContext()))
{
ClaimsIdentityFactory = new AppClaimsIdentityFactory()
};
// more initialization here
return manager;
}
3. Создайте новый пользовательский Principal
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Claims;
public class UserPrincipal : ClaimsPrincipal
{
public UserPrincipal(ClaimsPrincipal principal)
: base(principal.Identities)
{
}
public int UserId
{
get { return FindFirstValue<int>(ClaimTypes.NameIdentifier); }
}
public string UserName
{
get { return FindFirstValue<string>(ClaimsIdentity.DefaultNameClaimType); }
}
public string Email
{
get { return FindFirstValue<string>(ClaimTypes.Email); }
}
public string FirstName
{
get { return FindFirstValue<string>(ClaimTypes.GivenName); }
}
public string LastName
{
get { return FindFirstValue<string>(ClaimTypes.Surname); }
}
public string DisplayName
{
get
{
var name = string.Format("{0} {1}", this.FirstName, this.LastName).Trim();
return name.Length > 0 ? name : this.UserName;
}
}
public IEnumerable<int> Roles
{
get { return FindValues<int>(ClaimTypes.Role); }
}
private T FindFirstValue<T>(string type)
{
return Claims
.Where(p => p.Type == type)
.Select(p => (T)Convert.ChangeType(p.Value, typeof(T), CultureInfo.InvariantCulture))
.FirstOrDefault();
}
private IEnumerable<T> FindValues<T>(string type)
{
return Claims
.Where(p => p.Type == type)
.Select(p => (T)Convert.ChangeType(p.Value, typeof(T), CultureInfo.InvariantCulture))
.ToList();
}
}
4. Создайте AuthenticationFilter
, чтобы использовать его
using System.Security.Claims;
using System.Web.Mvc;
using System.Web.Mvc.Filters;
public class AppAuthenticationFilterAttribute : ActionFilterAttribute, IAuthenticationFilter
{
public void OnAuthentication(AuthenticationContext filterContext)
{
//This method is responsible for setting and modifying the principle for the current request though the filterContext .
//Here you can modify the principle or applying some authentication logic.
var principal = filterContext.Principal as ClaimsPrincipal;
if (principal != null && !(principal is UserPrincipal))
{
filterContext.Principal = new UserPrincipal(principal);
}
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
//This method is responsible for validating the current principal and permitting the execution of the current action/request.
//Here you should validate if the current principle is valid / permitted to invoke the current action. (However I would place this logic to an authorization filter)
//filterContext.Result = new RedirectToRouteResult("CustomErrorPage",null);
}
}
5. Зарегистрируйте фильтр авторизации для загрузки по всему миру в FilterConfig
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new AppAuthenticationFilterAttribute());
}
Теперь Principal
сохраняется, и все, что нам осталось сделать, это разоблачить его в контроллере и представлении.
6. Создание базового класса контроллера
public abstract class ControllerBase : Controller
{
public new UserPrincipal User
{
get { return HttpContext.User as UserPrincipal; }
}
}
7. Создайте базовый класс WebViewPage
и измените web.config
, чтобы использовать его
public abstract class BaseViewPage : WebViewPage
{
public virtual new UserPrincipal User
{
get { return base.User as UserPrincipal; }
}
public bool IsAuthenticated
{
get { return base.User.Identity.IsAuthenticated; }
}
}
public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
{
public virtual new UserPrincipal User
{
get { return base.User as UserPrincipal; }
}
public bool IsAuthenticated
{
get { return base.User.Identity.IsAuthenticated; }
}
}
И web.config
внутри папки Views
:
<pages pageBaseType="MyApp.Web.Views.BaseViewPage">
Внимание!
Не храните слишком много данных на Principal
, так как эти данные передаются взад и вперед по каждому запросу.