How can I get the specific fields of the currently logged-in user in MVC5?

前端 未结 2 1192
佛祖请我去吃肉
佛祖请我去吃肉 2021-01-06 02:08

I have an MVC5 app that uses Individual Authentication, and of course ASP.NET Identity. The point is that I had extended I have a model that inherits from ApplicationUser, i

相关标签:
2条回答
  • 2021-01-06 03:04

    In MVC5 the user data is stored by default in the session and upon request the data is parsed into a ClaimsPrincipal which contains the username (or id) and the claims.

    This is the way I chose to implement it, it might not be the simplest solution but it definitely makes it easy to use.

    Example of usage:

    In controller:

    public ActionResult Index()
    {
        ViewBag.ReverseDisplayName = this.User.LastName + ", " + this.User.FirstName;
    }
    

    In view or _Layout:

    @if(User.IsAuthenticated)
    {
         <span>@User.DisplayName</span>
    }
    

    1. Replace 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. Change the UserManager to use it

    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. Create a new custom 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. Create an AuthenticationFilter to use it

    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. Register the auth filter to load globally in the FilterConfig

    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute()); 
        filters.Add(new AppAuthenticationFilterAttribute());
    }
    

    By now the Principal is persisted and all we have left to do is expose it in the Controller and View.

    6. Create a controller base class

    public abstract class ControllerBase : Controller
    {
        public new UserPrincipal User
        {
            get { return HttpContext.User as UserPrincipal; }
        }
    }
    

    7. Create a WebViewPage base class and modify the web.config to use it

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

    And the web.config inside the Views folder:

    <pages pageBaseType="MyApp.Web.Views.BaseViewPage">
    

    Important!

    Do not store too much data on the Principal since this data is passed back and forth on each request.

    0 讨论(0)
  • 2021-01-06 03:07

    Yes, in Identity, if you need additional user information, you just pull the user from the database, since this is all stored on the actual user object now.

    if (Request.IsAuthenticated)
    {
        var user = UserManager.FindById(User.Identity.GetUserId());
    }
    

    If GetUserId isn't on User.Identity, add the following to your usings:

    using Microsoft.AspNet.Identity;
    
    0 讨论(0)
提交回复
热议问题