using custom IPrincipal and IIdentity in MVC3

12,404

Your mistake is here:

_application.AuthenticateRequest += ApplicationAuthenticateRequest;

There is a HttpModule named RoleManagerModule that invokes a method in HttpApplication.PostAuthenticateRequest and sets the HttpContext.Current.User to RolePrincipal. So, you were setting the User in AuthenticateRequest and the RoleManagerModule sets it in PostAuthenticateRequest, means after your set, so overrides your settings. Change your Module.Init:

public void Init(HttpApplication context) {
    _application = context;
    // change just this line:
    _application.PostAuthenticateRequest += ApplicationAuthenticateRequest;
}

IMPORTANT UPDATE:

Please see this question -asked by starter again, depended on current question- for a second solution, if this one doesn't work.

Share:
12,404
amiry jd
Author by

amiry jd

My other SO-Profile: https://stackoverflow.com/users/974276/j-amiry I am a hard-working and innovative developer with near 18 years of experience mostly based on .NET (Framework & Core) technology stack. For the last few years, alongside developing some awesome applications, I was focused on some non-coding tasks such as building up development teams, team leading, tech leading, problem solving, consulting, architecting, reviewing other's code, and mentoring. As a self-motivated fast-learner experienced code-guy, who has a proactive personality to step up to new challenges, I think I'm the man who can get the job done.

Updated on June 05, 2022

Comments

  • amiry jd
    amiry jd almost 2 years

    I create my own IPrincipal and IIdentity implementation as shown below:

    [ComVisible(true)]
    [Serializable]
    public sealed class CustomIdentity : IIdentity {
    
        private readonly string _name;
        private readonly string _email;
        // and other stuffs
    
        public CustomIdentity(string name) {
            _name = name.Trim();
            if(string.IsNullOrWhiteSpace(name))
                return;
            _email = (connect to database and read email and other stuffs);
        }
    
        public string Name {
            get { return _name; }
        }
    
        public string Email {
            get { return _email; }
        }
    
        public string AuthenticationType {
            get { return "CustomIdentity"; }
        }
    
        public bool IsAuthenticated {
            get { return !string.IsNullOrWhiteSpace(_name); }
        }
    
    }
    
    
    [ComVisible(true)]
    [Serializable]
    public sealed class CustomPrincipal : IPrincipal {
    
        private readonly CustomIdentity _identity;
    
        public CustomPrincipal(CustomIdentity identity) {
            _identity = identity;
        }
    
        public bool IsInRole(string role) {
            return _identity != null && 
                   _identity.IsAuthenticated &&
                   !string.IsNullOrWhiteSpace(role) &&
                   Roles.IsUserInRole(_identity.Name, role);
        }
    
        IIdentity IPrincipal.Identity {
            get { return _identity; }
        }
    
        public CustomIdentity Identity {
            get { return _identity; }
        }
    
    }
    

    Also, I create a HttpModule and in its AuthenticateRequest event, I do this:

        public void Init(HttpApplication context) {
            _application = context;
            _application.AuthenticateRequest += ApplicationAuthenticateRequest;
        }
    
        private void ApplicationAuthenticateRequest(object sender, EventArgs e) {
            var formsCookie = _application.Request.Cookies[FormsAuthentication.FormsCookieName];
            var identity = formsCookie != null
                 ? new CustomIdentity(FormsAuthentication.Decrypt(formsCookie.Value).Name)
                 : new CustomIdentity(string.Empty);
            var principal = new CustomPrincipal(identity);
            _application.Context.User = Thread.CurrentPrincipal = principal;
        }
    

    Also, I create my own Controller and WebViewPage like these:

    public abstract class CustomController : Controller {
        public new CustomPrincipal User {
            get {
                var user = System.Web.HttpContext.Current.User as CustomPrincipal;
                return user;
            }
        }
    }
    
    
    public abstract class CustomWebViewPage<TModel> : WebViewPage<TModel> {
        public new CustomPrincipal User {
            get {
                // (Place number 1) here is the error I'm speaking about!!!
                var user = HttpContext.Current.User as CustomPrincipal;
                return user;
            }
        }
    }
    

    as shown in above code, it seems everything is right; But as you can see, in Place number 1 I can't access the CustomPrincipal! Means in this place, I have a RolePrincipal instead of having a CustomPrincipal. e.g. HttpContext.Current.User is a RolePrincipal instead of CustomPrincipal. But the RolePrincipal.Identity property is a CustomIdentity!

  • David Keaveny
    David Keaveny almost 12 years
    Thanks for this answer; I was pulling my hair out trying to figure this one!
  • amiry jd
    amiry jd almost 12 years
    @DavidKeaveny Thank you, but I have to tell you the solution has a problem yet. Search in king.net's questions, you can find a Q associated on this one that there is another problem with IIS, so I suggest a way him/her, that resolve the issue fine. Please look at king.net's questions, you will find it. Regards.
  • David Keaveny
    David Keaveny almost 12 years
    Thanks for the heads-up; I'll keep an eye open for the issue when I deploy.