4

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

lancscoder
  • 8,658
  • 8
  • 48
  • 68

3 Answers3

6

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.

Brian Ball
  • 12,268
  • 3
  • 40
  • 51
0

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

dcaswell
  • 3,137
  • 2
  • 26
  • 25
0

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.

Steve Czetty
  • 6,147
  • 9
  • 39
  • 48