2
votes

I'm building a website in .Net MVC4 and am trying to implement my own forms authentication using a CustomPrincipal object.

Here is my Login method...

public void Login(string email)
{
    var user = _userManager.GetUserByEmail(email);

    var encryptedCookieContent = FormsAuthentication.Encrypt(new FormsAuthenticationTicket(1, user.Email, DateTime.Now, DateTime.Now.AddMinutes(FormsAuthentication.Timeout.TotalMinutes),
        false, user.Id + "|" + user.AccountId + "|" + user.RoleId + "|" + user.Role.Name, FormsAuthentication.FormsCookiePath));

    var formsAuthenticationTicketCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedCookieContent)
    {
        Domain = FormsAuthentication.CookieDomain,
        Path = FormsAuthentication.FormsCookiePath,
        HttpOnly = true,
        Secure = FormsAuthentication.RequireSSL
    };

    HttpContext.Current.Response.Cookies.Add(formsAuthenticationTicketCookie);
}

This is my Custom Principal

public class CustomPrincipal : IPrincipal
{
    public CustomPrincipal(IIdentity identity, int userId, int accountId, string role, int roleId)
    {
        Identity = identity;
        Role = role;
        RoleId = roleId;
        UserId = userId;
        AccountId = accountId;
    }

    public bool IsInRole(string role)
    {
        return Role == role;
    }

    public bool IsInRole(int roleId)
    {
        return RoleId == roleId;
    }

    public IIdentity Identity { get; private set; }

    public string Role { get; private set; }
    public int RoleId { get; private set; }

    public int UserId { get; private set; }
    public int AccountId { get; private set; }
}

I'm not implementing a custom instance of Identity, I'm just reusing the GenericIdentity. In my Global.asax file I've got my Application_AuthenticateRequest method rigged up like this...

protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
    if (Request.IsAuthenticated)
    {
        var formsCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
        if (formsCookie != null)
        {
            var ticket = FormsAuthentication.Decrypt(formsCookie.Value);
            var principal = PrincipalConfig.CreatePrincipal(ticket);
            System.Web.HttpContext.Current.User = Thread.CurrentPrincipal = principal;
        }
    }
}

PrincipalConfig.CreatePrincipal is the method that puts together my custom principal object. This basically just fills in userData... like this...

public static CustomPrincipal CreatePrincipal(FormsAuthenticationTicket ticket)
        {
            var userData =  ticket.UserData.Split('|');
            var principal = new CustomPrincipal(new GenericIdentity(ticket.Name), Convert.ToInt32(userData[0]), Convert.ToInt32(userData[1]), userData[3], Convert.ToInt32(userData[2]));
            return principal;
        }

So now, referring back to the Application_AuthenticateRequest in the global.asax file, you can see that I'm taking my newly created CustomPrincipal object and assigning it to System.Web.HttpContext.Current.User.

After doing so, if I put the following in the immediate window while still in the Application_AuthenticateRequest method...

System.Web.HttpContext.Current.User as CustomPrincipal

I am shown all of the data in my CustomPrincipal object just as I would expect.

However, if I later (in some other controller action) attempt to access the System.Web.HttpContext.Current.User and cast it as a CustomPrincipal it is returning a null.

Again, for each request that is made in the application I am able to decrypt the FormsAuthenticationTicket from the FormsAuthentication cookie inside of the Application_AuthenticateRequest method and I find all of my UserData. So it seems that the cookie is being created and read properly. But when the new CustomPrincipal is assigned to System.Web.HttpContext.Current.User, there seems to be some sort of disconnect from that time to the time that I attempt to access it again inside another controller.

Can anyone see what I might be doing wrong here?

Let me know if I need to clarify anything.

Thanks

1

1 Answers

0
votes

I am not sure you are using

Request.IsAuthenticated

correctly.

The Request.IsAuthenticated property essentially returns the same value as the Context.User.Identity.IsAuthenticated property. In your code, it should always return false, so the code that assigned the custom principal will never fire.

You can debug this a bit by setting a breakpoint in your controller method and inspecting the type of Context.Current.User in your code. Is it GenericIdentity? If so, your principal was never assigned.