MVC Custom Authentication, Authorization, and Roles Implementation

后端 未结 3 1595
星月不相逢
星月不相逢 2020-12-13 02:53

Bear with me as I provide details for the issue...

I\'ve got an MVC site, using FormsAuthentication and custom service classes for Authentication, Autho

相关标签:
3条回答
  • 2020-12-13 03:27

    While I think you're doing a fine job with this, I question why you are recreating the wheel. Since microsoft provides a system for this, called Membership and Role Providers. Why not just write a custom membership and role provider, then you don't have to create your own authization attribute and/or filters and can just use the inbuilt one.

    0 讨论(0)
  • 2020-12-13 03:34

    Cross-post from my CodeReview answer:

    I'll take a stab at answering your questions and provide some suggestions:

    1. If you have FormsAuthentication configured in web.config, it will automatically pull the cookie for you, so you shouldn't have to do any manual population of the FormsIdentity. This is pretty easy to test in any case.

    2. You probably want to override both AuthorizeCore and OnAuthorization for an effective authorization attribute. The AuthorizeCore method returns a boolean and is used to determine whether the user has access to a given resource. The OnAuthorization doesn't return and is generally used to trigger other things based on the authentication status.

    3. I think the session-vs-cookie question is largely preference, but I'd recommend going with the session for a few reasons. The biggest reason is that the cookie is transmitted with every request, and while right now you may only have a little bit of data in it, as time progresses who knows what you'll stuff in there. Add encryption overhead and it could get large enough to slow down requests. Storing it in the session also puts ownership of the data in your hands (versus putting it in the client's hands and relying on you to decrypt and use it). One suggestion I would make is wrapping that session access up in a static UserContext class, similar to HttpContext, so you could just make a call like UserContext.Current.UserData. See below for example code.

    4. I can't really speak to whether it is a good separation of concerns, but it looks like a good solution to me. It's not unlike other MVC authentication approaches I've seen. I'm using something very similar in my apps in fact.

    One last question -- why did you build and set the FormsAuthentication cookie manually instead of using FormsAuthentication.SetAuthCookie? Just curious.

    Example code for static context class

    public class UserContext
    {
        private UserContext()
        {
        }
    
        public static UserContext Current
        {
            get
            {
                if (HttpContext.Current == null || HttpContext.Current.Session == null)
                    return null;
    
                if (HttpContext.Current.Session["UserContext"] == null)
                    BuildUserContext();
    
                return (UserContext)HttpContext.Current.Session["UserContext"];
            }
        }
    
        private static void BuildUserContext()
        {
            BuildUserContext(HttpContext.Current.User);
        }
    
        private static void BuildUserContext(IPrincipal user)
        {
            if (!user.Identity.IsAuthenticated) return;
    
            // For my application, I use DI to get a service to retrieve my domain
            // user by the IPrincipal
            var personService = DependencyResolver.Current.GetService<IUserBaseService>();
            var person = personService.FindBy(user);
    
            if (person == null) return;
    
            var uc = new UserContext { IsAuthenticated = true };
    
            // Here is where you would populate the user data (in my case a SiteUser object)
            var siteUser = new SiteUser();
            // This is a call to ValueInjecter, but you could map the properties however
            // you wanted. You might even be able to put your object in there if it's a POCO
            siteUser.InjectFrom<FlatLoopValueInjection>(person);
    
            // Next, stick the user data into the context
            uc.SiteUser = siteUser;
    
            // Finally, save it into your session
            HttpContext.Current.Session["UserContext"] = uc;
        }
    
    
        #region Class members
        public bool IsAuthenticated { get; internal set; }
        public SiteUser SiteUser { get; internal set; }
    
        // I have this method to allow me to pull my domain object from the context.
        // I can't store the domain object itself because I'm using NHibernate and
        // its proxy setup breaks this sort of thing
        public UserBase GetDomainUser()
        {
            var svc = DependencyResolver.Current.GetService<IUserBaseService>();
            return svc.FindBy(ActiveSiteUser.Id);
        }
    
        // I have these for some user-switching operations I support
        public void Refresh()
        {
            BuildUserContext();
        }
    
        public void Flush()
        {
            HttpContext.Current.Session["UserContext"] = null;
        }
        #endregion
    }
    

    In the past I had put properties directly on the UserContext class for accessing the user data I needed, but as I've used this for other, more complicated projects, I decided to move it to a SiteUser class:

    public class SiteUser
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string FullName
        {
            get { return FirstName + " " + LastName; }
        }
        public string AvatarUrl { get; set; }
    
        public int TimezoneUtcOffset { get; set; }
    
        // Any other data I need...
    }
    
    0 讨论(0)
  • 2020-12-13 03:39

    Your MVC Custom Authentication, Authorization, and Roles Implementation looks good. To answer your first question, when you are not using a membershipprovider you have to populate the FormsIdentity principal yourself. A solution I use is described here My Blog

    0 讨论(0)
提交回复
热议问题