mellis481
mellis481

Reputation: 4158

Trouble retaining CustomPrincipal type in HttpContext

I have an MVC app which I'm having trouble ex[posing a custom principal to my views. It has the following classes that help me manage auth cookies.

public class AuthenticationManager
{
    public void SetAuthCookie(UserViewModel user)
    {
        var serializeModel = new CustomPrincipalSerializeModel
        {
            Id = user.UserId,
            Email = user.Email,
            Name = user.Name
        };
        var serializer = new JavaScriptSerializer();
        var customPrincipal = customPrincipalMapper.Convert(serializeModel);
        var httpContext = ContextHelper.GetHttpContextBase();
        httpContext.User = customPrincipal;
        var userData = serializer.Serialize(serializeModel);
        var authTicket = new FormsAuthenticationTicket(1, serializeModel.Email, DateTime.Now, DateTime.Now.AddYears(5), false, userData);
        var encTicket = FormsAuthentication.Encrypt(authTicket);
        var authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
        httpContext.Response.Cookies.Add(authCookie);
    }
}

public static class ContextHelper
{
    public static HttpContextBase GetHttpContextBase()
    {
        return new HttpContextWrapper(HttpContext.Current);
    }
}

I also have the following BaseViewPage classes which allow me to expose the current user to my views:

public abstract class BaseViewPage : WebViewPage
{
    public virtual new CustomPrincipal User
    {
        get { return base.User as CustomPrincipal; }
    }
}

public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
{
    public virtual new CustomPrincipal User
    {
        get { return base.User as CustomPrincipal; }
    }
}

FWIW, this requires <pages pageBaseType="Giftster.Web.Views.BaseViewPage"> to be in my View's Web.config file.

Immediately, after the httpContext.User = customPrincipal; line runs in AuthenticationManager.SetAuthCookie(), the type of object which ContextHelper.GetHttpContextBase().User returns is a CustomPrincipal. If I refresh the page, however, and put a break point in BaseViewPage, base.User as CustomPrincipal (and ContextHelper.GetHttpContextBase().User as CustomPrincipal for that matter) equals null. base.User is not null, though: It is of type GenericPrincipal, so there is either a casting issue or a problem with storing/retrieving the correct type.

Why is base.User in my BaseViewPage not of type CustomPrincipal?

Thanks in advance.

Upvotes: 0

Views: 192

Answers (1)

user3559349
user3559349

Reputation:

You need to create your CustomPrincipal from the cookie in each request and add it to the current context. Add the following to the Global.asax.cs file

protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
{
  // Get the authentication cookie
  HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
  // If the cookie can't be found, don't issue the ticket
  if (authCookie == null)
  {
    return;
  }
  // Extract the forms authentication cookie
  FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
  // Deserialise user data
  JavaScriptSerializer serializer = new JavaScriptSerializer();
  CustomPrincipalSerializeModel data = serializer.Deserialize<CustomPrincipalSerializeModel>(authTicket.UserData);
  // Create principal
  CustomPrincipal principal = new CustomPrincipal(authTicket.Name);
  // Set the properties of CustomPrincipal
  principal.Email = data.Email;
  .... // etc
  // Assign to current context
  HttpContext.Current.User = principal;
}

Note also the following line is not required in you SetAuthCookie() method

httpContext.User = customPrincipal;

You might also consider adding the following to a BaseController (from which all other controllers derive) so the CustomPrincipal properties can be accessed easily in each controller method

public new CustomPrincipalSerializeModel User
{
  get { return (CustomPrincipal)HttpContext.User; }
}

Upvotes: 1

Related Questions