4
votes

I am trying to get some custom field values from my authentication ticket by running the following code in my controller -

[HttpPost]
    public ActionResult Add(AddCustomerModel customer)
    {
        customer.DateCreated = DateTime.Now;
        customer.CreatedBy = ((CustomPrincipal)(HttpContext.User)).Id;
        customer.LastUpdated = DateTime.Now;
        customer.LastUpdateBy = ((CustomPrincipal)(HttpContext.User)).Id;

        if (ModelState.IsValid)
        {
            _customerService.AddCustomer(customer);

            return RedirectToAction("Index");
        }

        return View(customer);
    }

When I try and set the CreatedBy field for the new customer, I get the following error -

Unable to cast object of type 'System.Security.Principal.GenericPrincipal' to type 'GMS.Core.Models.CustomPrincipal'.

My userData field within the FormsAuthenticationTicket is set with a JSON string which contains two fields - Id and FullName.

Here is my login method on the controller -

    [HttpPost]
    [AllowAnonymous]
    public ActionResult Login(LoginModel model, string returnUrl)
    {
        if (Membership.ValidateUser(model.EmailAddress, model.Password))
        {
            LoginModel user = _userService.GetUserByEmail(model.EmailAddress);

            CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel();
            serializeModel.Id = user.ID;
            serializeModel.FullName = user.EmailAddress;
            //serializeModel.MergedRights = user.MergedRights;

            JavaScriptSerializer serializer = new JavaScriptSerializer();

            string userData = serializer.Serialize(serializeModel);

            FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
             1,
             user.EmailAddress,
             DateTime.Now,
             DateTime.Now.AddHours(12),
             false,
             userData);

            string encTicket = FormsAuthentication.Encrypt(authTicket);
            HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
            Response.Cookies.Add(faCookie);

            return RedirectToAction("Index", "Dashboard");
        }

        return RedirectToAction("Index");
    }

Any ideas where I am going wrong?

2
Do you have a protected void Application_PostAuthenticateRequest(object sender, EventArgs e) method in Global.asax where you create the CustomPrincipal and assign it to HttpContext.Current.User?user3559349

2 Answers

4
votes

To retrieve the userdata from cookies you can use the following code

FormsIdentity formsIdentity = HttpContext.Current.User.Identity as FormsIdentity;
FormsAuthenticationTicket ticket = formsIdentity.Ticket;
string userData = ticket.UserData;
0
votes

You need to create and AuthenticationFilter to change your GenericPrincipal to your CustomPrincipal

public class FormAuthenticationFilter : ActionFilterAttribute, IAuthenticationFilter
{
    private readonly IResolver<HttpContextWrapper> httpContextWrapper;

    private readonly IResolver<ISecurityProvider> securityProviderResolver;

    public FormAuthenticationFilter(IResolver<HttpContextWrapper> httpContextWrapper, IResolver<ISecurityProvider> securityProviderResolver)
    {
        this.httpContextWrapper = httpContextWrapper;
        this.securityProviderResolver = securityProviderResolver;
    }

    public void OnAuthentication(AuthenticationContext filterContext)
    {
        if (filterContext.Principal != null && !filterContext.IsChildAction)
        {
            if (filterContext.Principal.Identity.IsAuthenticated &&
                filterContext.Principal.Identity.AuthenticationType.Equals("Forms", StringComparison.InvariantCultureIgnoreCase))
            {
                // Replace form authenticate identity
                var formIdentity = filterContext.Principal.Identity as FormsIdentity;
                if (formIdentity != null)
                {
                    var securityProvider = this.securityProviderResolver.Resolve();
                    var principal = securityProvider.GetPrincipal(filterContext.Principal.Identity.Name, formIdentity.Ticket.UserData);
                    if (principal != null)
                    {
                        filterContext.Principal = principal;
                        this.httpContextWrapper.Resolve().User = principal;
                    }
                }
            }
        }
    }

    public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
    {
    }
}

And then register that filter to GlobalFilter

GlobalFilters.Filters.Add(new FormAuthenticationFilter());

The HttpContextWrapper in my code is just the wrapper of HttpContext.Current. You can change it to whatever you need. And the IAuthenticationFilter only exist in MVC 5.