Search code examples
asp.netasp.net-mvcasp.net-mvc-4asp.net-web-apiforms-authentication

Where to read Forms authentication cookie?


I have implemented Forms authentication in one project. In the forms authentication cookie I store the Login Id of the user. i.e.

FormsAuthentication.SetAuthCookie(LoginId, false); 

I now need to read the cookie value on every request to get more information about the user and put this information in the HttpContext.Items property. The project is a MVC project that has both regular MVC Controllers as well as Web API controllers. Currently I have created two action filters - one for the MVC controllers and other for Web API Controllers where I read this value. So like

public class MyMvcFilter : AuthorizeAttribute 
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
        if (cookie != null)
        {
            var ticket = FormsAuthentication.Decrypt(cookie.Value);
            filterContext.HttpContext.Items.Add("LoginId",ticket.Name);
        }


        base.OnAuthorization(filterContext);
    }
}

and

public class MyFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        base.OnActionExecuting(actionContext);

        var cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
        if (cookie == null)
        {
            return;
        }
        var ticket = FormsAuthentication.Decrypt(cookie.Value);
        if (ticket == null)
        {
            return;
        } 

        actionContext.Request.Properties.Add("LoginId", userId);

    }
}

However the more I think of it, the more it looks like an ugly hack to me. What would be correct location where I can decrypt the authentication cookie and remains the same for MVC controller as well as Web API controller ?


Solution

  • I would:

    1. Read the cookie on the

      protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
      {
      
      }
      
    2. In the above method....Convert the cookie to a ClaimsPrincipal. Like the below:

      protected void Application_PostAuthenticateRequest(object sender, EventArgs e)
      {
      
      
      
         IList<Claim> claimCollection = new List<Claim>
          {
              new Claim("http://www.mycompany.com/claims/LoginId, "123456" /* use info from cookie instead of 123456*/)
          };
      
          ClaimsIdentity claimsIdentity = new ClaimsIdentity(claimCollection, "My e-commerce website");
      
          Console.WriteLine(claimsIdentity.IsAuthenticated);
      
          ClaimsPrincipal customPrinc = new ClaimsPrincipal(claimsIdentity);
      
          if (null != customPrinc)
          {
              Thread.CurrentPrincipal = customPrinc; /* Set here.  But when you need to "get" it, use "System.Security.Claims.ClaimsPrincipal.Current" */
              /* ASP.NET Authorization depends on value of HttpContext.Current.User.
               * Consider putting ClaimsPrincipal  into both  HttpContext.Current.User and Thread.CurrentPrincipal */
              HttpContext.Current.User = customPrinc; 
      
             /* Note the second setter is necessary so you don't lose it later on, learned the hard way by experience */
          }
      }
      

    Retrieve the Claims Principal as needed..

        /* MVC */
        public override void OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext)
        {
            /* the below should be what you set in the Application_PostAuthenticateRequest method */
            IPrincipal currentClaimsPrinc = ClaimsPrincipal.Current;
    
        }
    
    
        /* WebAPI */
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            IPrincipal claimsPrincCurrent = ClaimsPrincipal.Current;
    
        }
    

    You could also do this:

    adding claims to forms authentication in asp.net

    or this:

    http://brockallen.com/2013/01/26/replacing-forms-authentication-with-wifs-session-authentication-module-sam-to-enable-claims-aware-identity/

    or this:

    http://chris.59north.com/post/Claims-based-identities-in-ASPNET-MVC-45-using-the-standard-ASPNET-providers