This is me blogging the experience of programming at the speed of me. I work mostly on web apps and Windows Phone 7 and enjoy writing about the ups and downs of development in those spaces. I program on the .NET stack, am lovin' Windows 7 and Visual Studio 2010. Truth be told, the only ones that call me 'Mister James' are the three- and four-year-olds at Sunday school. But I'll take what I can get...

Pages

This blog has, IMO, some great resources. Unfortunately, some of those resources are becoming less relevant. I'm still blogging, learning tech and helping others...please find me at my new home on http://www.jameschambers.com/.

Wednesday, January 19, 2011

Built-In Authentication and Authorization Providers in ASP.NET with the MVC Framework

If you’re not already doing so, you should seriously be using the the built-in Auth & Auth in ASP.NET. While the subject is fairly well covered, I continue to get several questions and comments related to creating accounts, logging in and permissions and when talking with other developers. I am shocked at how many still roll their own authentication and authorization bits – often for no better reason than not knowing how great (and FREE!) the default providers are.

The Basics of Authentication and Authorization

There are two things you will need to do on most web sites with “account” functionality: identify existing users based on provided user names and passwords (authentication) and then express privileges to control access to protected resources (authorization).

These two facilities allow us to do some creative things, like showing different content to users when they are logged in, or to restrict and redirect requests based on the logged in user’s set of privileges.

In ASP.NET, Auth & Auth are Free

The first official, for-a-customer e-commerce web site that I notched on my belt was back in 1997. I spent days creating a system to log users in, store cookies (that I do not care to discuss security about!), store user information, track log-ins and the like. Each page that I wanted to protect with security meant checking cookies for certain keys, looking those keys up, then checking against a static set of rules for permissions. I spent weeks fixing the broken parts. Because most of it was wrapped up in per-page scripts, I had to essentially recreate the whole mess when the customer decided they wanted to self-administer the storefront.

Today, so much of that mess is cleaned up for us. I want to give you the steps to set up Authentication and Authorization in your next MVC web site.

Open Visual Studio 2010 and create a new ASP.NET MVC 2 Web Application.

Yeup. We’re done.

Walking Through What’s There

If you are familiar with the MVC pattern the default project is quite straightforward, but not entirely trivial. There is no magic here, just convention and after working with the project for a few minutes you should be able to orient yourself.

The three basic concepts of MVC – Model, View and Controller – are expressed as classes and .aspx pages (as well as .ascx for partial pages and templates). As part of the convention, each part has it’s own directory, and in the View folder we have subfolders for each controller.

The Project Components

What is relevant to us today are the items related to user accounts. You can see that there is an AccountController for us as well as the classes we need to log a user on in AccountModels. The Account subfolder in Views gives us four pages dealing with account creation, maintenance and sign on. Finally, the Shared subfolder in Views has a LogOnUserControl that displays different content based on the authentication status of the user.

At this point, we’re actually still missing a couple of pieces. If you drill into your App_Data directory you would find that there is no database to hold your account data. Thankfully, we don’t need to do much to create one; namely, we just use the site.

The Registration Process

Press F5 to start debugging the application. When the site opens up you’ll see the default master page and index in action:

Follow the Log On link up in the top right corner of the page. This will take you to a page with a form to log on, but also a link to the registration page. Follow that, and create an admin account.

Once you’ve created your account you can return to the App_Data directory and see that the database has been created (you may need to click the show all button in the Solution Explorer).

The show all button looks like this:

Authorization In An Attribute

This is where the easy kicks in.

To add authorization to your application you can make use of the attributes available to us in the ASP.NET MVC Framework. It is as simple as adding one line of code to your controller.

Let’s turn our about page into something that only authenticated users can view.

Perfect! The [Authorize] attribute describes the controller action as something that only users who have been authenticated can access. And now, when we load up our site, if we try to navigate to the About page prior to logging in you will be redirected to the login page. To prove this, start debugging the site and add /home/about to your URL. You’ll see this:

After logging in, you can see the About page in all its empty glory. In fact, because your request was originally for the About page, the default AccountController pushes you through to that page once you’ve authenticated.

Some MVC Sweetness

Views in ASP.NET MVC inherit from the System.Web.Mvc.ViewPage object and therefor expose some interesting objects for us that we don’t have to work for to use. Taking advantage of this fact allows us to shortcut to some features right in our views.

For example, the User object on our ViewPage allows us to test for authenticated users:

Or, we can test to see if they belong to roles in the ASP.NET membership/role provider:

While this can be super handy, it’s important to consider coding practices and whether or not your logic for such elements should be in your controller or your view. This post will not enter that conversation, but it’s important to note that a similar roles-based approach is just as easy inside your controller:

Oh Yeah, About Those Roles

The easiest way to get roles going would be to navigate to the ASP.NET Configuration site. You can enable and define roles from there:

This built-in administration tool simplifies the process of enabling roles on your site, adding existing users to roles and/or creating roles and bringing in existing users. It also allows you to add a role to a user as you create them. It’s tidy and functional, but doesn’t have many bells and whistles.

This isn’t the best for a production environment as the ASP.NET Configuration site is not deployed when you publish your app. One solution would be to use a community-based console to help administer the site post-launch such as this one.

Some Reading Homework

I recently had the privilege of working with one of the authors of this book (Stephen Walther) and I can attest to the fact that these guys know this stuff inside and out.

ASP.NET 4 Unleashedcontains a ton of great information on using and abusing the .NET Framework when working on web applications, including a section devoted to the membership framework.

Conclusion

We’ve come a long way in web development. Tasks that used to require “rolling your own” and a day or a week of dedicated time can now be reduced to simply clicking on “New –> Project”.

The beauty in that is that way that we can fully customize those bits, integrate them with our existing auth/auth stores and more. We can choose our view engine (classic ASP.NET, MVC or now Razor). We can integrate jazzy Ajax features through the fully supported jQuery libraries and its good-looking sister, jQuery UI.

4 comments:

Hi Nice post. Was wondering whether I could post a comment related to authorisation and authentication seeing as you have a good post on this. My situation is such that I am working on an application that requires user authentication but this is going to be an internal application and so I decided to create an employees table that has a UserId foreign key from the aspnet_users table. My Employee fields are firstname lastname, nationalId etc and UserId (foreign key). I managed to create a dropdownlist that actually displays the users but I can't get it it to post the userId value from the dropdown. My create (post) action method is can't post without this required field. I am using VS 2010, EF .Net 4 and MVC2

Thanks for the great article... I'm one of those people who've chosen to "role their own" a number of times - even though this is built in. I've done that mostly because I always need to tie other data in other tables to the authenticated user. Do you know of any other articles out there that detail the best way to do that?

Hey Leftend: I was in the exact same boat as you in this regard, but realized that it's just an SQL database. You are free to add whatever tables you like to the mix. On top of that, you can easily filter out the aspnet_ tables (right-click on the Tables folder) and just work with your own. Use your UserID for the custom tables.

Ignatius: Without being able to look specifically at the code or data, I'm going to just have to suggest that you attach your debugger and start digging.

Two things you'll want to do: first, install Firefox and Firebug (a developer plug in for Firefox). I find this easier to deal with the client-side of things for debugging.

Second, set the required breakpoints in your app and start walking through the code in your controller/repository.

You will need to first nail down if you're getting the data to the client (what's the value of the combo box selection?) and then if the param's getting posted properly (use Firebug) and finally, what you're getting on the action method (breakpoint).

Certifications

A Bit About Me

From a technical perspective, I am a .Net developer, devoted to keeping up with new areas of learning. I try to grow in this regard through continued education, access to literature and time devoted to mentoring others -- a great way to learn. Most recently I have worked in the areas of development around ASP.NET MVC, Windows Phone 7, Windows Azure and the likes. I am a little too crazy about Linq (check out my Linq statement to convert IP addresses to decimals for proof). I lead our local .Net User Group and enjoy speaking publicly and the opportunity to teach to a large group of people. Personally, I am someone who believes in giving back to the community and my family is blessed to be able to give many hours to local and national charities, community organizations and to our church.