|
The first thing I did was take an out-of-the-box MVC application created using the recently released ASP.NET 3.5 Extensions Preview. In keeping with the advice I had mentioned in previous blog posts, I do not create IIS-based web projects anymore, I exclusively build Cassini-based (integrated VS 2008 filesystem-based web projects that are self-hosted in "Cassini" , the ASP.NET development web server) projects.
Once I had my starting point, complete with routes, I needed to secure the web application so that only the URLs associated with logging in and creating a new user were available to unauthenticated people. For that, you end up using the <location/> element in your web.config (I won't go into the syntax here, it should be old hat for ASP.NET 2.0+ programmers). Next, you need to set up the providers, which is actually a two-step process.
First, you need to prep a SQL database (you can use other stores, but I'm exclusively using the SQL providers for this sample). To do this, use SQL 2005 (you're not using SQL Express are you???) and create a new database and leave it empty. Create an account that has full permissions on that DB. For my system, I created a DB called AspNetSystemServices with an account called, interestingly enough, aspnet.
Next, open up a VS 2008 command prompt (in Administrator mode if you're on Vista...) and fire up aspnet_regsql with no command-line arguments. This will bring up a wizard that will prompt you for the information on how to connect to the database that will be prepped for system services (such as roles, membership, profiles, and customization).
Almost there. Now we need to rig up the providers in the Web.config file. First thing you need is the connection string for the provider, which you put in the <connectionStrings/> element in Web.config. Then, set up the <membership/> element, the <roleManager/> element, and the <profile/> element. There are plenty of samples available for these, and if you want me to go into detail, post a comment and I'll post those snippets of my web.config later.
Great! At this point, you should have a system that is denying anonymous users access (<authorization><deny users="?"/></authorization> in your <system.web> element), but you also allow them to access the "/Login" location. Coincidentally, that location is the location of your login controller, which you'll create right now.
Create a new controller in the Controllers folder called LoginController. First thing you need is to add a method for Index , which will display the standard login page prompting for the username and password. Then you want a method that actually performs the login on a form post. I called mine DoLogin but feel free to come up with something more clever, like perhaps PerformLogin or for the linguist in you EffectLogin.
In the Index() method of the login controller, we're just going to do RenderView("Index"); So let's take a look at the contents of the Index.aspx MVC view (remember to make this an actual View Page and not just a random ASP.NET page):
<html>blah
.. you are not logged in...
<form action="/Login/DoLogin" method="post">
..
<input type="text" name="userName"/>
<input type="password" name="userPassword"/>
<input type="submit" ....
</form></html>
This is where the MVC stuff starts to kick in. This form is going to call the "DoLogin" method on the "LoginController" class when the result is posted. In addition, the userName and userPassword form parameters are going to be converted into individual parameters for the method (you can also do it in bulk, but I like the clarity of named parameters) call. Here's a look at the DoLogin controller method:
public void DoLogin(string userName, string userPassword)
{
if (Membership.ValidateUser(userName, userPassword))
{
FormsAuthentication.SetAuthCookie(userName, true);
RedirectToAction( new { Action = "Index", Controller = "Home" } );
}
else
{
TempData["LoginMessage"] = "The username and password supplied are not valid.";
RedirectToAction( new { Action = "Index" } );
}
}
We have to use the FormsAuthentication class to write the auth ticket since we're not using the standard login control (which uses a postback... postback is for l4merz and n00bz!). The Index.aspx view can inspect the contents of the TempData (transient dictionary that lasts only one request, perfect for "flash"ing a single message between state changes, eh?) property and display the warning message. At this point, the auth cookie will be written for valid users and those users will see the output of the HomeController's Index method.
Finally, we can write some code in the HomeController's Index.aspx view to display the currently logged in user, which should look very familiar to anyone who has written code to the ASP.NET 2.0 provider model in the past:
<% if (User.Identity.IsAuthenticated) { %>
Sweet, we love your kind here, Mr. <%= User.Identity.Name %>
<% } else { %>
Be gone, n00bsauce.
<% } %>I realize the look of some of this inline code might scare a lot of people who've been doing ASP.NET for a long time, and the burned out, cranky old ASP.NET developer inside me shrieks in revulsion when I see this... but the agile guy inside me who loves Rails isn't so bothered by this stuff.
So in short, with very little effort and no hacking, I got the ASP.NET provider model fired up in my MVC project and I'm now using it to authenticate my MVC application users, and will be shortly using it to do role management and profile management as well.
That's right people, I'm not just having my cake and eating it too, I'm eating my cake with peanut butter on it.