I need to do something fairly simple: in my ASP.NET MVC application, I want to set a custom IIdentity / IPrincipal. Whichever is easier / more suitable. I want to extend the default so that I can call something like User.Identity.Id
and User.Identity.Role
. Nothing fancy, just some extra properties.
I've read tons of articles and questions but I feel like I'm making it harder than it actually is. I thought it would be easy. If a user logs on, I want to set a custom IIdentity. So I thought, I will implement Application_PostAuthenticateRequest
in my global.asax. However, that is called on every request, and I don't want to do a call to the database on every request which would request all the data from the database and put in a custom IPrincipal object. That also seems very unnecessary, slow, and in the wrong place (doing database calls there) but I could be wrong. Or where else would that data come from?
So I thought, whenever a user logs in, I can add some necessary variables in my session, which I add to the custom IIdentity in the Application_PostAuthenticateRequest
event handler. However, my Context.Session
is null
there, so that is also not the way to go.
I've been working on this for a day now and I feel I'm missing something. This shouldn't be too hard to do, right? I'm also a bit confused by all the (semi)related stuff that comes with this. MembershipProvider
, MembershipUser
, RoleProvider
, ProfileProvider
, IPrincipal
, IIdentity
, FormsAuthentication
…. Am I the only one who finds all this very confusing?
If someone could tell me a simple, elegant, and efficient solution to store some extra data on a IIdentity without all the extra fuzz.. that would be great! I know there are similar questions on SO but if the answer I need is in there, I must've overlooked.
Best Answer
Here's how I do it.
I decided to use IPrincipal instead of IIdentity because it means I don't have to implement both IIdentity and IPrincipal.
Create the interface
CustomPrincipal
CustomPrincipalSerializeModel - for serializing custom information into userdata field in FormsAuthenticationTicket object.
LogIn method - setting up a cookie with custom information
Global.asax.cs - Reading cookie and replacing HttpContext.User object, this is done by overriding PostAuthenticateRequest
Access in Razor views
and in code:
I think the code is self-explanatory. If it isn't, let me know.
Additionally to make the access even easier you can create a base controller and override the returned User object (HttpContext.User):
and then, for each controller:
which will allow you to access custom fields in code like this:
But this will not work inside views. For that you would need to create a custom WebViewPage implementation:
Make it a default page type in Views/web.config:
and in views, you can access it like this: