Custom Principal reverting to GenericPrincipal on new requests

2.3k views Asked by At

I'm trying to implement a custom principal and custom identity in a .NET MVC website. I've created a custom principal class which inherits from IPrincipal and a custom identity which inherits from IIdentity.

When a user logs in I set both Thread.CurrentPrincipal and HttpContext.Current.User to my custom principal. When I view either through the debugger the values are set with all the properties.

However once the request is complete and I try and request any other pages both Thread.CurrentPrincipal and HttpContext.Current.User are of type System.Security.Principal.GenericPrincipal and not my custom principal.

Do I need to do anything "extra" to get my custom principal out of the thread or HttpContext?

Thanks

3

There are 3 answers

0
Brian Ball On BEST ANSWER

The values in Thread.CurrentPrincipal and HttpContext.Current.User are not persisted between requests, they are rebuilt on each request. The best place for you to do this is probably in the Global.asax; write a function with the prototype:

void Application_PostAuthenticateRequest(object sender, EventArgs e)

That should get called after a user is authenticated on each request, which will allow you to set the principal how you would like.

0
Steve Czetty On

I would like to expand on the accepted answer slightly, hopefully I can save somebody a little bit of time.

In my case, the principal I used contained claims that were populated from the results of an external service, so I wanted to cache the results at login time.

I created a simple cache interface, IUserPrincipalCache, and registered it with the MVC DependencyResolver. At login, I build up the principal and add it to the cache. (Since your implementation may vary, I'll leave all that out.)

I then implemented this in Global.asax.cs:

protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
    if (User.Identity.IsAuthenticated)
    {
        var cache = DependencyResolver.Current.GetService<IUserPrincipalCache>();
        var claimsPrincipal = cache.FindUser(User.Identity.Name);
        if (claimsPrincipal != null)
        {
            Context.User = claimsPrincipal;
            Thread.CurrentPrincipal = claimsPrincipal;
        }
    }
}

I think it is important to point out the check for IsAuthenticated, since I could bypass the cache check in many cases. You also may not need to update Thread.CurrentPrincipal, I guess that depends on how you're using it.

0
user2907569 On

Overridding Principal in:

protected void Application_PostAuthenticateRequest(object sender, EventArgs e)

Instead of

protected void Application_AuthenticateRequest(object sender, EventArgs e)

In Global.asax.cs worked for me in an ASP web application