Custom Identity using MVC5 and OWIN

后端 未结 4 1821
轻奢々
轻奢々 2021-01-30 11:33

I trying to add custom properties to the ApplicationUser for a web site using MVC5 and OWIN authentication. I\'ve read https://stackoverflow.com/a/10524305/264607 and I like ho

4条回答
  •  离开以前
    2021-01-30 12:18

    You're getting an exception because HttpContext.Current.User.Identity.IsAuthenticated returns false at the point of check (so does HttpContext.Current.Request.IsAuthenticated).

    If you remove the if (HttpContext.Current.User.Identity.IsAuthenticated) statement it will work fine (at least this part of code).

    I've tried a simple thing like this:

    BaseController.cs

    public abstract class BaseController : Controller
    {
        protected virtual new CustomPrincipal User
        {
            get { return HttpContext.User as CustomPrincipal; }
        }
    }
    

    CustomPrincipal.cs

    public class CustomPrincipal : IPrincipal
    {
        public IIdentity Identity { get; private set; }
        public bool IsInRole(string role) { return false; }
    
        public CustomPrincipal(string username)
        {
            this.Identity = new GenericIdentity(username);
        }
    
        public DateTime BirthDate { get; set; }
        public string InvitationCode { get; set; }
        public int PatientNumber { get; set; }
    }
    

    Global.asax.cs

    protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
    {
         CustomPrincipal customUser = new CustomPrincipal(User.Identity.Name);
    
         customUser.BirthDate = DateTime.Now;
         customUser.InvitationCode = "1234567890A";
         customUser.PatientNumber = 100;
    
         HttpContext.Current.User = customUser;
    }
    

    HomeController.cs

    public ActionResult Index()
    {
        ViewBag.BirthDate = User.BirthDate;
        ViewBag.InvitationCode = User.InvitationCode;
        ViewBag.PatientNumber = User.PatientNumber;
    
        return View();
    }
    

    And this is working fine. So unless this code:

    userManager = new UserManager(new UserStore(new ApplicationDbContext()));
    
    ApplicationUser user = userManager.FindByName(HttpContext.Current.User.Identity.Name);
    

    is not returning a valid (custom) user object, the problem is with the if() statement.

    Your update looks fine, and if you're happy to store data as claims in a cookie you can go with it, although I personally hate the try {} catch block there.

    What I do instead is this:

    BaseController.cs

    [AuthorizeEx]
    public abstract partial class BaseController : Controller
    {
        public IOwinContext OwinContext
        {
            get { return HttpContext.GetOwinContext(); }
        }
    
        public new ClaimsPrincipal User
        {
            get { return base.User as ClaimsPrincipal; }
        }
    
        public WorkContext WorkContext { get; set; }
    }
    

    I decorate the base controller class with a custom attribute.

    AuthorizeExAttribute.cs:

    public class AuthorizeExAttribute : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            Ensure.Argument.NotNull(filterContext);
    
            base.OnAuthorization(filterContext);
    
            IPrincipal user = filterContext.HttpContext.User;
            if (user.Identity.IsAuthenticated)
            {
                var ctrl = filterContext.Controller as BaseController;
                ctrl.WorkContext = new WorkContext(user.Identity.Name);
            }
        }
    }
    

    And WorkContext.cs:

    public class WorkContext
    {
        private string _email;
    
        private Lazy currentUser;
    
        private IAuthenticationService authService;
        private ICacheManager cacheManager;
    
        public User CurrentUser
        {
            get 
            { 
                var cachedUser = cacheManager.Get(Constants.CacheUserKeyPrefix + this._email);
                if (cachedUser != null)
                {
                    return cachedUser;
                }
                else
                {
                    var user = currentUser.Value;
    
                    cacheManager.Set(Constants.CacheUserKeyPrefix + this._email, user, 30);
    
                    return user;
                }
            }
        }
    
        public WorkContext(string email)
        {
            Ensure.Argument.NotNullOrEmpty(email);
    
            this._email = email;
    
            this.authService = DependencyResolver.Current.GetService();
            this.cacheManager = DependencyResolver.Current.GetService();
    
            this.currentUser = new Lazy(() => authService.GetUserByEmail(email));
        }
    

    I then access the WorkContext like this:

    public class DashboardController : BaseController
    {
        public ActionResult Index()
        {
            ViewBag.User = WorkContext.CurrentUser;
    
            return View();
        }
    }
    

    I'm using Ninject's Dependency Resolver to resolve authService and cacheManager but you can skip caching and replace authService with ASP.NET Identity UserManager I believe.

    I also wanted to give credit where it's due as the WorkContext class is heavily inspired by NugetGallery project.

提交回复
热议问题