I've written a custom principal object which contains a few additional fields (email and userid in addition to the username).
In order to access these properties I have to cast the Context.User object as my custom principal.
@Html.GetGravitarImage((User as CustomPrincipal).Email)
This custom principal is created / deserialized via the Application_AuthenticateRequest in my global.ascx. You can see this question I asked here for more information.
private void Application_AuthenticateRequest(Object source, EventArgs e)
{
var application = (HttpApplication)source;
var context = application.Context;
// Get the authentication cookie
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = context.Request.Cookies[cookieName];
if (authCookie == null)
return;
var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
context.User = CustomPrincipal.CreatePrincipalFromCookieData(authTicket.UserData);
}
However, if a user isn't authenticated, then my cast to CustomPrincipal will fail (because it won't be injected in the method above) and the result of the (User as CustomPrincipal) will return null, thus giving me a null reference exception when my method above attempts to get the email.
What would be a clean solution to this problem? I want to make accessing my custom principal easy and having to do the following seems cumbersome:
@Html.GetGravitarIcon((User is CustomPrincipal) ? (User as CustomPrincipal).Email : "Default Email")
Is this the only way to handle this situation?
When not authorized, you could set the user object to a specific instance of the custom principal with default values:
I whipped something together quickly. One possible way of easily introducing a custom IPrincipal in ASP.NET MVC is the following:
1) Create your own descendant of the IPrincipal interface.
2) Let's assume you are using the ASP.NET Membership provider to authenticate your users. Let's quickly build an IMyPrincipal implementation which utilizes the membership API.
3) Create your own base class type for your controllers. Hide the inherited User member and introduce your own IPrincipal descendant.
4) Have all your controllers descend from this new BaseController type.
5) Create your own controller factory to make sure your principal is introduced on the HttpContext / Thread.
6) Register the controller factory in the Global.asax's Application_Start() event handler.
Voila, now you can use the new User (IMyPrincipal) anywhere in your controllers.
For example:
You could also make extension methods for the Email and UserID in the same fashion as John Kalberer's answer:
You could either create a base class and override the "User" property using the "new" keyword or create an extension method like this:
The best way to make your
IPrincipal
implementation accessible in your Razor pages using ASP.NET MVC, is doing the following:System.Security.Principal.IPrincipal
interface.System.Security.Principal.IIdentity
interface.Global.asax
define a method for:void Application_AuthenticateRequest(Object, EventArgs)
that persists your both implementations ofIPrincipal
andIIdentity
.IPrincipal
to expose your implementation ofIIdentity
.<system.web.webPages.razor>
.At the end, you will be able to access your custom implementation of
IIdentity
instead of type casting. You now can access your custom implementation like this:These steps are a concise and brief description of a well detailed article written here: http://rizzo7.blogspot.com/2012/04/mvc-30-razor-custom-principal-and.html
You could create some sort of utility method or add a method to one of your services that checks if it's your custom principal. Maybe something like: