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

前端 未结 2 1224
佛祖请我去吃肉
佛祖请我去吃肉 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)
    {
         @User.DisplayName
    }
    

    1. Replace ClaimsIdentityFactory

    using System.Security.Claims;
    using System.Threading.Tasks;
    using Domain.Models;
    using Microsoft.AspNet.Identity;
    
    public class AppClaimsIdentityFactory : IClaimsIdentityFactory
    {
        internal const string IdentityProviderClaimType = "http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider";
    
        internal const string DefaultIdentityProviderClaimValue = "My Identity Provider";
    
        /// 
        ///     Constructor
        /// 
        public AppClaimsIdentityFactory()
        {
            RoleClaimType = ClaimsIdentity.DefaultRoleClaimType;
            UserIdClaimType = ClaimTypes.NameIdentifier;
            UserNameClaimType = ClaimsIdentity.DefaultNameClaimType;
            SecurityStampClaimType = Constants.DefaultSecurityStampClaimType;
        }
    
        /// 
        ///     Claim type used for role claims
        /// 
        public string RoleClaimType { get; set; }
    
        /// 
        ///     Claim type used for the user name
        /// 
        public string UserNameClaimType { get; set; }
    
        /// 
        ///     Claim type used for the user id
        /// 
        public string UserIdClaimType { get; set; }
    
        /// 
        ///     Claim type used for the user security stamp
        /// 
        public string SecurityStampClaimType { get; set; }
    
        /// 
        ///     Create a ClaimsIdentity from a user
        /// 
        /// 
        /// 
        /// 
        /// 
        public virtual async Task CreateAsync(UserManager 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 Create(IdentityFactoryOptions options, IOwinContext context)
    {
        var manager = new UserManager(new UserStore(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(ClaimTypes.NameIdentifier); }
        }
    
        public string UserName
        {
            get { return FindFirstValue(ClaimsIdentity.DefaultNameClaimType); }
        }
    
        public string Email
        {
            get { return FindFirstValue(ClaimTypes.Email); }
        }
    
        public string FirstName
        {
            get { return FindFirstValue(ClaimTypes.GivenName); }
        }
    
        public string LastName
        {
            get { return FindFirstValue(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 Roles
        {
            get { return FindValues(ClaimTypes.Role); }
        }
    
        private T FindFirstValue(string type)
        {
            return Claims
                .Where(p => p.Type == type)
                .Select(p => (T)Convert.ChangeType(p.Value, typeof(T), CultureInfo.InvariantCulture))
                .FirstOrDefault();
        }
    
        private IEnumerable FindValues(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 : WebViewPage
    {
        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:

    
    

    Important!

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

提交回复
热议问题