Click here to Skip to main content
15,860,861 members
Articles / Web Development / ASP.NET

Using a Cookie-Aware WebClient to Persist Authentication in ASP.NET MVC

Rate me:
Please Sign up or sign in to vote.
5.00/5 (9 votes)
22 Jul 2013CPOL4 min read 50K   9   9
This post will cover how to create a simple “cookie-aware” WebClient class that will authenticate and persist this authentication for the duration of the WebClient to allow access to secure areas of your MVC Application without the need for re-authenticating for each request.

Earlier this year, I was working on an iPhone application that interacted with a running ASP.NET MVC site and the need arose for the iPhone user to authenticate so that they could access some of the Actions within a Controller decorated with the lovely [Authorize] attribute. This post will cover how to create a simple “cookie-aware” WebClient class that will authenticate and persist this authentication for the duration of the WebClient to allow access to secure areas of your MVC Application without the need for re-authenticating for each request.

The Problem

You are using a very basic ASP.NET MVC Application with integrated Forms Authentication and the need arises for you to authenticate and access multiple controller actions, which require authentication, using a single WebClient.

The Solution

Me want cookie.

Cookies can easily be persisted within a WebClient object to eliminate the need to continually authenticate each request.

In order to handle this issue, we will need to create a custom WebClient class that will persist our authentication token for the duration of our “visit” based on parameters that were passed in. This can be accomplished by creating a class that will inherit from the WebClient class and will have a specific container to house the authentication cookie:

C#
//Cookie-Aware WebClient
public class CookieAwareWebClient : WebClient
{
  //An aptly named container to store the Cookie
  public CookieContainer CookieContainer { get; private set; }

  public CookieAwareWebClient()
  {
    CookieContainer = new CookieContainer();
  } 
}

In its current state – this fails to actually do anything except create an extra CookieContainer property that we can’t really do anything with as we will need to determine a way to actually populate the authentication cookie and store it within the WebClient from any of the Requests that are made through the client itself.

This can be handled by adding the following snippet of code within the CookieAwareWebClient class:

C#
protected override WebRequest GetWebRequest(Uri address)
{
    //Grabs the base request being made 
    var request = (HttpWebRequest)base.GetWebRequest(address);
    //Adds the existing cookie container to the Request
    request.CookieContainer = CookieContainer;

    return request;
}

The above code will associate the current Request that is being made from the WebClient and add the appropriate cookie to handle any future requests made by the client.

Digging in the Cookie Jar

The following example details how to use the newly created Cookie-Aware WebClient within an MVC environment by allowing the current user (in this instance from an iOS Application built through Xamarin) to authenticate using the standard AccountController available in ASP.NET MVC and then call a method from a Controller that is decorated with the [Authorize] attribute.

Let’s take a look at exactly what we want to access through our iOS call:

C#
[Authorize]
public class SecureController : Controller
{
    //A secure method that will be accessed through your iOS Application
    public ActionResult YourSecureMethod(string data)
    {
        return Content(String.Format("{0} was passed in.",data);
    }
}

As you can see, there isn’t really anything special about the Controller or the Action besides the [Authorize] decoration at the Controller level, which is great because we don’t really want to have to do anything special to handle this functionality.

Now – within your iOS application, we are going to make two calls (the first to authenticate and the second to make the actual call itself) within an instance of the WebClient:

C#
//Create an instance of your new CookieAware Web Client
using (var client = new CookieAwareWebClient())
{
   //Authenticate (username and password can be either hard-coded or pulled from a settings area)
   var values = new NameValueCollection{{ "UserName", username },{ "Password", password }};

   //Perform authentication - after this has been performed
   //the cookie will be stored within the Web Client
   client.UploadValues(new Uri("http://www.yourdomain.com/Account/LogOn/"), "POST", values);

   //Authentication worked! Access the secure area (you can use a
   //variety of methods here such as UploadFile, UploadValues, etc.)
   client.UploadString(new Uri("http://www.yourdomain.com/Secure/YourSecureMethod"), 
     "POST", "Example Message");           
}

And that’s really all you need as you could call a multitude of other Controller Actions within the context of your WebClient. It should be noted that your authentication values will only persist during the using statement and any further attempts to access your application outside of it will require additional authentication.

More Chocolate-Chips to Add to the Cookies

This is just one of the many examples of the Web Client being extended to assist with a very simple requirement that previous several redundant calls from being made within a simple Request. Another feature that I found to be incredibly helpful is implementing a Timeout mechanism for your WebClient.

Timing out can be essential when dealing with requests from iOS devices, as most users don’t want to sit there and wait indefinitely for a password that they accidentally left the CAPS LOCK key on for to be rejected. For this reason, implementing a timeout can put a stop to a request after a specific amount of time and notify the user that they will need to retry their request.

All you will need to do to handle this will be to add an integer property to the WebClient class:

C#
//An optional timeout property
private int? _timeout = null;
public int? Timeout
{
    get { return _timeout;  }
    set { _timeout = value; }
}

along with a method on your WebClient to handle setting it:

C#
public void SetTimeout (int timeout)
{
    _timeout = timeout;
}

and then finally, you’ll need to actually use it when your WebRequests are being made, so you can add the logic in there as well:

C#
protected override WebRequest GetWebRequest(Uri address)
{
    var request = (HttpWebRequest)base.GetWebRequest(address);
    request.CookieContainer = CookieContainer;
        //Sets a timeout for the Request if the timeout property is available
    if (_timeout.HasValue) {
        request.Timeout = _timeout.Value;
    }
    return request;
}

So after all that, now you would just need to set the property (if you need it) after declaring your WebClient:

C#
using (var client = new CookieAwareWebClient()) 
{
    //Times out after 5 minutes
    client.SetTimeout (5 * 60 * 1000);
        //I found that on iOS devices that the KeepAlive header can be helpful
        // (but it is likely not completely necessary in most instances)
    client.Headers [HttpRequestHeader.KeepAlive] = "true";

        //Code
}

Too. Much. Chocolate.

If this post made you hungry and you are too overwhelmed or are edging towards a cookie-coma, don’t fret. I won’t make you go through the extended trouble of copy-pasting the entire class above from all of those separate snippets. You can download the class from github below in case the need ever arises that you should require something even remotely like it or you would want to use it to further extend:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
An experienced Software Developer and Graphic Designer with an extensive knowledge of object-oriented programming, software architecture, design methodologies and database design principles. Specializing in Microsoft Technologies and focused on leveraging a strong technical background and a creative skill-set to create meaningful and successful applications.

Well versed in all aspects of the software development life-cycle and passionate about embracing emerging development technologies and standards, building intuitive interfaces and providing clean, maintainable solutions for even the most complex of problems.

Comments and Discussions

 
GeneralMy vote of 5 Pin
salky_cro10-Nov-16 21:45
salky_cro10-Nov-16 21:45 
QuestionWill this work with the new ASP.NET Identity? Pin
HHGClark28-Feb-16 11:05
HHGClark28-Feb-16 11:05 
QuestionExcellent! Pin
Dennis Fazekas3-Dec-15 2:00
Dennis Fazekas3-Dec-15 2:00 
GeneralIts Worked!!! Great Work!!!! Pin
Sanket17223-Nov-15 20:36
Sanket17223-Nov-15 20:36 
PraiseYou solution worked great! Pin
gknath2-Nov-15 8:14
gknath2-Nov-15 8:14 
QuestionCookieAwareWebClient doesn't work with JSP page Pin
Pavel_4727-Mar-15 1:10
Pavel_4727-Mar-15 1:10 
QuestionThanks ! Pin
Fred68torino3-Jan-15 1:59
Fred68torino3-Jan-15 1:59 
GeneralA great solution! :) Pin
AntiManglement25-Nov-14 13:13
AntiManglement25-Nov-14 13:13 
GeneralMy vote of 5 Pin
Assil15-Aug-14 8:54
professionalAssil15-Aug-14 8:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.