User Authentication 2
12 Jun 2009 @ 08:25AM

Updated: 8 Apr 2010 @ 12:32PM
We've set the stage. Now we'll continue by adding a new line as the first thing in the Page_Load() method as so:
protected void Page_Load(object sender, EventArgs e)
{
     authenticate();

And now for the magic, the authenticate() method. I'm going to post out the athenticate() method and all the other changes and we'll discuss it afterward.
private bool loggedIn = false;
private int userid;
private string username;
private string displayName;
private string email;
private bool showEmail;
private DateTime createDate;
private int accessLevel;

public enum clean{
     DB
}

private void authenticate()
{
     string _username = null, password = null;
     if (getVariable("username", var.POST) != null && getVariable("password", var.POST) != null)
     {
          _username = sanitize(getVariable("username", var.POST), clean.DB);
          password = FormsAuthentication.HashPasswordForStoringInConfigFile(getVariable("password", var.POST), "MD5");
     }

     if (_username == null || password == null)
     {
          return;
     }

     string select = "SELECT userid, username, displayName, email, showEmail, createDate, accessLevel " +
          "FROM users WHERE username='" + _username + "' AND password='" + password + "'";
     SqlDataReader dr = query(select);
     if (dr.HasRows)
     {
          dr.Read();
          loggedIn = true;
          userid = Convert.ToInt16(dr["userid"]);
          username = Convert.ToString(dr["username"]);
          displayName = Convert.ToString(dr["displayName"]);
          email = Convert.ToString(dr["email"]);
          showEmail = (Convert.ToInt16(dr["showEmail"]) == 1) ? true : false;
          createDate = Convert.ToDateTime(dr["createDate"]);
          accessLevel = Convert.ToInt16(dr["accessLevel"]);
     }
     else
     {
          loggedIn = false;
     }
     dr.Dispose();
}

private string sanitize(string value, clean type)
{
     switch (type)
     {
          case clean.DB:
               value = value.Replace("'", "''");
               break;
     }

     return value;
}

Ok, first thing we have is a series of variables (loggedIn=false, userid, etc etc). These are set outside of any method, making them class properties. That just means they're variables that can be accessed from within any method. This is handy in case you have variables you may need elsewhere and you don't want to have to get them all the time. In this case, we have a bool called loggedIn that will tell us if a user is logged in or not. We then have a series of variables that are linked to fields in the users table. This way we can query the users table once and get all the variables we may need.
Comments (0)
public enum clean{
     DB
}

Following that we have another enum named clean. This has a single option at the moment, DB. This will be used in our sanitize() method which we'll get to.
Comments (0)
private void authenticate()
{
     string _username = null, password = null;

Next we have our actual authenticate() method. We begin by initializing two variables, _username and password. Why _username and not username? Because we have username already defined as a class property and we don't want to cause ourselves any additional confusion. So why don't we have password as a class property? The reason is that other than for authentication, we never need the password for anything. Even if we allow a user to change or reset the password, we will never, ever need the actual value of the password.
Comments (0)
if (getVariable("username", var.POST) != null && getVariable("password", var.POST) != null)
{
     _username = sanitize(getVariable("username", var.POST), clean.DB);
     password = FormsAuthentication.HashPasswordForStoringInConfigFile(getVariable("password", var.POST), "MD5");
}

So on the next line we find an if statement. We're using the getVariable() method to retrieve two POST variables by the name of username and password. These would be passed to us by the login form we worked on earlier. The getVariable() method is lower down and you can see where we added the logic to get POST variables. Back to the authenticate() method, if the POST variables of username and password are both not null, we set _username = sanitize(getVariable("username", var.POST), clean.DB);. On the inside of this, you see we're just reinvoking getVariable() to pull the POSTed username. We then run that through the sanitize() method and an option of clean.DB. This is what the enum was for earlier.
Comments (0)
private string sanitize(string value, clean type)
{
     switch (type)
     {
          case clean.DB:
               value = value.Replace("'", "''");
               break;
     }

     return value;
}

Here is our sanitize() method. Basically we did the same thing in an ealier tutorial. This allows us to escape any single quotes that someone may have entered in with their username, saving us from a potential SQL injection later on. Following that assignment, we set password = FormsAuthentication.HashPasswordForStoringInConfigFile(getVariable("password", var.POST), "MD5");. We use getVariable() to grab the POST password variable again, then invoke this long method that's part of .Net. Basically we're just taking the password passed to us by POST and running it through an MD5 hash. The FormsAuthentication class we're using above requires using the Systen.Web.Security namespace. As usual, just type it out and wait for the red underline to show at the end of the word, then use intellisense to add the namespace for you automatically.
Comments (0)
if (_username == null || password == null)
{
     return;
}

Next we check to see if _username or password are null... if they are, we just return, thereby aborting any further processing for our authenticate() method.
string select = "SELECT userid, username, displayName, email, showEmail, createDate, accessLevel " +
"FROM users WHERE username='" + _username + "' AND password='" + password + "'";
SqlDataReader dr = query(select);
if (dr.HasRows)
{
     dr.Read();
     loggedIn = true;
     userid = Convert.ToInt16(dr["userid"]);
     username = Convert.ToString(dr["username"]);
     displayName = Convert.ToString(dr["displayName"]);
     email = Convert.ToString(dr["email"]);
     showEmail = (Convert.ToInt16(dr["showEmail"]) == 1) ? true : false;
     createDate = Convert.ToDateTime(dr["createDate"]);
     accessLevel = Convert.ToInt16(dr["accessLevel"]);
}
else
{
     loggedIn = false;
}
dr.Dispose();

On to the next statement, we start building a select statement. Basically we're just trying to retrieve all our fields we want and set the where clause to the username and md5 hashed password the user supplied. This is why we sanitized the username input and why we hashed the password. Why didn't we sanitize the password? There's no reason to... an md5 hash will never contain characters that we'll need to sanitize. It doesn't matter what the user may have put in for the password... once we hash it, it's safe. With the select statement created, we query the database. If the SqlDataReader object HasRows(), that means at least one (and hopefully only one) row has been returned. If no rows have been returned, the username/password combo was wrong. If it does have a result, we just set loggedIn to true and populate all our class properties with the database results.

On the next page, we start taking advantage of our data and wrap up some loose ends.
Comments (0)