Tag Archives: membership

Storing Custom Data in Forms Authentication Tickets

This article looks at storing custom data in asp.net forms authentication tickets. I recently updated the article to make the custom model binder generic, and add the necessary registration code which was missing from the first draft.

So you’ve decided to use FormsAuthentication, and perhaps enhanced it with your own custom providers. In your AccountController Login method you probably have a call along these lines:

FormsAuthentication.SetAuthCookie(account.Id.ToString(), model.RememberMe);

That all works great, but what if you need to store some extra data in the cookie. Perhaps the name you are passing into the AuthTicket isn’t actually the users name, but a GUID. Suddenly that built in ASP.Net login widget, in the top right of the page, doesn’t seem so great when it looks like this:

Hello 5D1D4743-9941-40B5-8931-6BC12617946C

What we need to do is store some extra data in that AuthTicket cookie right? That way we can keep the GUID as the authentication id, but still store things like the users first name in the cookie. Thus saving an expensive round trip to the db each time we render the widget.

Hmmm… whats this ‘UserData’ property we see on the AuthTicket? Perfect!

Erk… It’s read only?!?!?!

At least that’s how my thought process went.

So we need to make an authentication ticket ourselves:

var ticket = FormsAuthenticationTicket(int version, string name, DateTime issueDate,
	DateTime expiration, bool isPersistent, string userData, string cookiePath);

Unfortunately that’s quite a few more parameters than SetAuthCookie(…) required and they should be coming from the web.config rather than hard-coded.

On the plus side, there is access to the UserData!

To avoid losing the web.config driven settings, we can do a little trick and get FormsAuthentication to do the parsing for us. All we need to do is ask it for an AuthTicket and copy the settings from that into a new one we create.

To do this, a few steps are required. Firstly, after getting the ticket, we have to decrypt it, copy the data into a new ticket, and then make sure we encrypt that. Then we need to add it to the response.

Now before getting to the code, we should think about where it should live. It would seem logical to encapsulate this an extension method on FormsAuthentication, but being a static class we can’t. Instead we can attach it to HttpResponseBase which is not a bad home, especially as we have to add the cookie onto a response anyway. I’d recommend creating the following class in an ‘Infrastructure’ folder in your project:

	public static class HttpResponseBaseExtensions
	{
		public static int SetAuthCookie<T>(this HttpResponseBase responseBase, string name, bool rememberMe, T userData)
		{
			/// In order to pickup the settings from config, we create a default cookie and use its values to create a 
			/// new one.
			var cookie = FormsAuthentication.GetAuthCookie(name, rememberMe);
			var ticket = FormsAuthentication.Decrypt(cookie.Value);
			
			var newTicket = new FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration,
				ticket.IsPersistent, userData.ToJson(), ticket.CookiePath);
			var encTicket = FormsAuthentication.Encrypt(newTicket);

			/// Use existing cookie. Could create new one but would have to copy settings over...
			cookie.Value = encTicket;

			responseBase.Cookies.Add(cookie);

			return encTicket.Length;
		}
	}

There are a couple of things of note here, firstly we are accepting a generic type for the UserData, and secondly we are encoding it to Json!

Why? well lets think about the UserData field. Being on a cookie, this can only contain string data. Now we could do our own custom serialisation into this string, but my preference is to use JSON as it’s designed for the task. In this instance I’m using the serialiser from MongoDb as I happen to be using that in my project, but any Json serialiser will do. You might like to try the ServiceStack implementation for example.

I’m also returning the size of the cookie – cookies should never be longer than 4000 bytes as some browsers will just discard them. Its worth keeping an eye on this as it’s not just the size of your UserData but the other mandatory parts of the cookie too.

So let’s get this wired into our AccountController.

First we define a UserData class with a FirstName in it:

	public class UserData
	{
		public string FirstName { get; set; }

		public UserData()
		{
			FirstName = "Unknown";
		}
	}

Now here’s an example Login Action. There are some extras in here around validation, but you can use whatever approach here that fits your project.

[HttpPost]
		public ActionResult LogIn(AccountLoginVM model, string returnUrl)
		{
			try
			{
				if (ModelState.IsValid)
				{
					// Some code to validate and check authentication
					if (!Membership.ValidateUser(model.Email, model.Password))
						throw new RulesException("Incorrect username or password");

					Account account = _accounts.GetByEmail(model.Email);

					UserData userData = new UserData
					{
						FirstName = account.FirstName
					};

					Response.SetAuthCookie(account.Id.ToString(),
						model.RememberMe, userData);
				
					if (Url.IsLocalUrl(returnUrl))
					{
						return Redirect(returnUrl);
					}
					else
					{
						return RedirectToAction("Index", "Home");
					}
				}
			}
			catch (RulesException ex)
			{
				ex.CopyTo(ModelState);
			}

			model.Password = "";
			return View(model);
		}

That’s it. We’ve now got a cookie with our extra UserData in it.

Hang on… what about fixing that login widget in the top right?

One elegant way to crack this is to create a custom model binder, then if we swap the example widget from being a partial view to a partial action, all we need to do is demand a UserData object as an input param and the magic of binding will save us.

So, the custom model binder, again leveraging the MongoDb Json deserialiser:

	/// <summary>
	/// Binder to pull the UserData out for any actions that may want it.
	/// </summary>
	public class UserDataModelBinder<T> : IModelBinder
	{
		public object BindModel(ControllerContext controllerContext,
			ModelBindingContext bindingContext)
		{
			if (bindingContext.Model != null)
				throw new InvalidOperationException("Cannot update instances");
			if (controllerContext.RequestContext.HttpContext.Request.IsAuthenticated)
			{
				var cookie = controllerContext
					.RequestContext
					.HttpContext
					.Request
					.Cookies[FormsAuthentication.FormsCookieName];

				if (null == cookie)
					return null;

				var decrypted = FormsAuthentication.Decrypt(cookie.Value);

				if (!string.IsNullOrEmpty(decrypted.UserData))
					return BsonSerializer.Deserialize<T>(decrypted.UserData);
			}
			return null;
		}
	}

This is a generic so you can use whatever class suits to store the userdata. This then needs to be registered in Application_Start() in ‘Global.asax.cs’ :

ModelBinders.Binders.Add(typeof(UserData), new UserDataModelBinder<UserData>());

Now our login widget action, which passes a UserData object into our view (wrapped in a view model as we may not always want to pass all the UserData into the view).

		public ActionResult LoginWidget(UserData userData)
		{
			AccountLoginWidgetVM model = new AccountLoginWidgetVM();
			if (null != userData)
				model.UserData = userData;

			return PartialView(userData);
		}
@model TestProj.Web.Models.AccountLoginWidgetVM
         
@if(Request.IsAuthenticated) {
    <text>Welcome <b>@Model.UserData.FirstName</b>!
    [ @Html.ActionLink("Logout", "Logout", "Account") ]</text>
}
else {
...
}

We’ve covered quite a broad range of topics here, but hopefully its clear and of use. If you need any clarification leave a comment.

Next time… a change of tack. I’m going to look at how to get some performance out of a devexpress WPF grid.

ASP.Net MVC 3 Custom Membership Provider with Repository Injection

In most serious ASP.NET MVC, or even legacy ASP.Net web sites, you are unlikely to want to use the default membership provider of ASP.Net. Its dependency on SQLServer and unhealthy predilection for littering databases with hundreds tables, just to support features you don’t care about, make it distinctly unattractive.

What we really want is to integrate our web site’s security with the project’s schema and bind directly to a table or repository encapsulating the users model for the site. The way to do this is through the implementation of a custom MembershipProvider.

This may seem a little daunting, but in practise is fairly simple. In fact, all we need do is override a pair of methods, on a couple of abstract classes, and all authentication and role checking will be routed to our code. Even better, by leveraging the well-tested and robust ASP.NET security facilities, we can still utilise the convenience and security of ASP.Net’s attribute based security to protect your controllers and controller methods. If you aren’t familiar with these, it’s as simple as attaching an Authorise tag, and optionally specifying a role the user must have to gain access e.g.

public class MemberController : Controller
{
	IAccountRepository repo;

	public MemberController(IAccountRepository accountRepository)
	{
		repo = accountRepository;
	}

	[Authorize]
	public ActionResult Index()
	{
...
	}

	[Authorize(Roles = "Admin")]
	public ActionResult Delete(int accountId)
	{
...
	}
}

Just being authorised means the user has been authenticated i.e. logged in. The role is supplementary to this and allows you finer grained access control. Easy huh?

So, firstly authentication. To take control of this, we have to create a class derived from the abstract class MembershipProvider.

Unfortunately, being a hangover from old-school ASP.net, wiring this in is a little more clumsy than one might expect. It predates the pluggable design pattern applied throughout the MVC platform. The upshot being, that if you want to use the repository pattern with it, you can’t pass a repository into the constructor as ASP.Net instantiates the class for you, and only knows how to do this through a default constructor.

One way to work around this is to make your repository a property on the class and update it after the framework has constructed it. In this example I’m going to use ninject as my DI framework, but you could use a different one, or in fact just set the property without using DI at all.

First lets start with an example membership provider. I’ve only bothered to override ValidateUser() as the other methods aren’t required to leverage ASP.NET’s integrated security features.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using Ninject;

namespace MyProj.Web.Infrastructure
{
	public class AccountMembershipProvider : MembershipProvider
	{
		[Inject]
		public IAccountRepository AccountRepository { get; set; }

		public override string ApplicationName
		{
			get
			{
				throw new NotImplementedException();
			}
			set
			{
				throw new NotImplementedException();
			}
		}

... lots of unimplemented overrides...

		public override void UpdateUser(MembershipUser user)
		{
			throw new NotImplementedException();
		}

		public override bool ValidateUser(string username, string password)
		{
			return AccountRepository.IsValidLogin(username, password);
		}
	}
}

You’ll notice there is an AccountRepository being used here to validate the user login. This is where your custom authorisation logic goes – as such I’m not going to provide an implementation here as it will depend on the specifics of your site.

Next, we need to ensure that the AccountRepository is injected into our MembershipProvider, and the place to do this is Application_Start() in Gloabl.asax.

	internal class MyNinjectModules : NinjectModule
	{
		public override void Load()
		{
			Bind<IAccountRepository>()
				.To<AccountRepository>();
		}
	}

	public class MvcApplication : System.Web.HttpApplication
	{
		private IKernel _kernel = new StandardKernel(new MyNinjectModules());

...code deleted....

		protected void Application_Start()
		{
			AreaRegistration.RegisterAllAreas();

			RegisterGlobalFilters(GlobalFilters.Filters);
			RegisterRoutes(RouteTable.Routes);

			// Inject account repository into our custom membership provider.
			_kernel.Inject(Membership.Provider);
		}
	}

You’ll notice that I’m grabbing the framework instantiated instance of our membership provider, and using ninject to set the repository property on our custom membership provider.

I’m also setting up a ninject controller factory which is a great class when you want to inject repositories into your controller’s constructors. This is based on code found in one of the best programming books I’ve ever read Pro ASP.NET MVC 2 Framework by Steven Sanderson. This book covers so much more than ASP.NET MVC, it teaches you how to design and build applications for testability, and is the most digestable explanation of modern test driven design I’ve ever come across. It’s worth a read even if you aren’t an MVC programmer! n.b. I believe a revised MVC3 edition is to be released shortly.

public class NinjectControllerFactory : DefaultControllerFactory
	{
		private IKernel _kernel;

		public NinjectControllerFactory(IKernel kernel)
		{
			_kernel = kernel;
		}

		protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
		{
			if (controllerType == null)
				return null;
		 
			return (IController)_kernel.Get(controllerType);
		}
	}

Now… what if we want to create a custom role provider too? Well that’s easy. Here is an exampe RoleProvider:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using Ninject;

namespace MyProj.Web.Infrastructure
{
	public class AccountRoleProvider : RoleProvider
	{
		[Inject]
		public IAccountRepository AccountRepository { get; set; }

		public override void AddUsersToRoles(string[] usernames, string[] roleNames)
		{
			throw new NotImplementedException();
		}

... lots of unimplemented overrides...

		public override string[] GetRolesForUser(string id)
		{
			return AccountRepository.GetRoles(id);
		}

... lots of unimplemented overrides...

		public override bool RoleExists(string roleName)
		{
			throw new NotImplementedException();
		}
	}
}

Again, you really don’t need to override much of the RoleProvider abstract class, simply implementing GetRolesForUser() and ensuring it returns a string array of the given users roles will suffice.

To inject the membership provider juat change the previous code version of Application_Start() to:

	public class MvcApplication : System.Web.HttpApplication
	{
		private IKernel _kernel = new StandardKernel(new MyNinjectModules());

...code deleted....

		protected void Application_Start()
		{
			AreaRegistration.RegisterAllAreas();

			RegisterGlobalFilters(GlobalFilters.Filters);
			RegisterRoutes(RouteTable.Routes);

			// Inject account repository into our custom membership & role providers.
			_kernel.Inject(Membership.Provider);
			_kernel.Inject(Roles.Provider);
		}
	}

Finally we need to register our providers in web.config:

<configuration>
...
  <system.web>
...
    <membership defaultProvider="AccountMembershipProvider">
      <providers>
        <clear/>
        <add name="AccountMembershipProvider"
             type="MyProj.Web.Infrastructure.AccountMembershipProvider" />
      </providers>
    </membership>

    <roleManager enabled="true" defaultProvider="AccountRoleProvider">
      <providers>
        <clear/>
        <add name="AccountRoleProvider"
             type="MyProj.Web.Infrastructure.AccountRoleProvider" />
      </providers>
    </roleManager>
...
  </system.web>
...  
</configuration>

It really us as simple as that!

One other note, if you are implementing your own password storage, make sure you hash them! (and I recommend you look at bcrypt for that).