User Authentication 3
12 Jun 2009 @ 08:53AM

Updated: 26 Jan 2010 @ 02:33PM
At this point, we basically have our authenticate() method. Every time the page loads, we check for the username/password, and if they exist, we run it against the db to log the user in. That's what we want, though we're not actually doing anything with the data yet. Let's change that with the menu.
private string layout()
{
     string content = @" <center><img src='header.png'></center>
          <div class='rightBar'>
               <div class='title'>C# Blog Menu</div>
               <ul>
                    <li>"
;
     content += (loggedIn) ? "<a href='default.aspx?logon=false'>Log Out</a>" : "<a href='default.aspx?logon=true'>Log In </a>";
     content += "</li>";
     if (loggedIn && accessLevel == 255)
     {
          content += @"<li><a href=''>Create Account</a></li>
                    <li><a href=''>Write Blog Entry</a></li>
                    <li><a href=''>See New Entries</a></li>"
;
     }
     content += @"</ul>
          </div>"
;
     return content;
}

So now we've altered our menu to display different options depending on whether or not the user is logged in. Additionally, if the user is logged in and has an accessLevel of 255, we display 3 options we don't display otherwise. This is fairly straight forward, but shows what can be done once you have authentication set up on your site.
Comments (0)
Now let's improve the usability a little. At the moment, if you try to log in with a wrong username and password, it just takes you back to the main screen without any kind of feedback. Let's fix that by making a few changes to the authenticate() method.
else
{
     loggedIn = false;
     if (getVariable("username", var.POST) != null && getVariable("password", var.POST) != null)
     {
          loginFailed = true;
     }
}

The above snippet is from the else statement in the authenticate() method. If authentication fails and the POST variables have been set, I set a class property called loginFailed to true. This is a new property, so be sure to create it in your class. It will be a private bool.
Comments (0)
Next, within the Page_Load() method I make this small change.
if (getVariable("logon", var.GET) == "true" || loginFailed)
{
     content += showLogon();
}

Now if the loginFailed, we execute the showLogon() method again. Lastly, we make a few changes here.
private string showLogon()
{
     string content = @"<center><div class='login'>
          <form method='POST' action='default.aspx'>
               Username: <input name='username'><br>
               Password: <input name='password' type='password'><br>
               <div class='button'><input type='submit' value='Log In'></div>"
;
     if (loginFailed)
     {
          content += "<div class='error'>The username/password combination is invalid</div>";
     }
     content += @"</form>
     </div></center>"
;

     return content;}

In here, if the loginFailed, we spit out an error message. Now the user has some feedback. If you've played around with this, you may notice a problem though. When you authenticate once, the menu shows exactly what you would expect. However, if you click on a link to go to another page, suddenly you're logged out again. Why's this? The reason is that we have nothing peristent to carry our loggedIn status around with us. We get logged in because we posted the username and password, but any subsequent link doesn't have that info and we're no longer logged in. We need to take care of that through the use of sessions and cookies. Follow on below.
Comments (0)
Next, within the Page_Load() method I make this small change.
if (getVariable("logon", var.GET) == "true" || loginFailed)
{
     content += showLogon();
}

Now if the loginFailed, we execute the showLogon() method again. Lastly, we make a few changes here.
private string showLogon()
{
     string content = @"<center><div class='login'>
          <form method='POST' action='default.aspx'>
               Username: <input name='username'><br>
               Password: <input name='password' type='password'><br>
               <div class='button'><input type='submit' value='Log In'></div>"
;
     if (loginFailed)
     {
          content += "<div class='error'>The username/password combination is invalid</div>";
     }
     content += @"</form>
     </div></center>"
;

     return content;}

In here, if the loginFailed, we spit out an error message. Now the user has some feedback. If you've played around with this, you may notice a problem though. When you authenticate once, the menu shows exactly what you would expect. However, if you click on a link to go to another page, suddenly you're logged out again. Why's this? The reason is that we have nothing peristent to carry our loggedIn status around with us. We get logged in because we posted the username and password, but any subsequent link doesn't have that info and we're no longer logged in. We need to take care of that through the use of sessions and cookies. Follow on below.
Comments (0)
private void authenticate()
{
     string _username = null, password = null;
     if (getVariable("username", var.POST) != null && getVariable("password", var.POST) != null)
     {     //check for POST vars from the login form
          _username = sanitize(getVariable("username", var.POST), clean.DB);
          password = FormsAuthentication.HashPasswordForStoringInConfigFile(getVariable("password", var.POST), "MD5");
     }
     else if (Session["blogUsername"] != null && Session["blogPassword"] != null)
     {     //check for sessions
          _username = sanitize(Session["blogUsername"].ToString(), clean.DB);
          password = sanitize(Session["blogPAssword"].ToString(), clean.DB);
     }
     else
     {     //check for cookies
          HttpCookie usernameCookie = HttpContext.Current.Request.Cookies["blogUsername"];
          HttpCookie passwordCookie = HttpContext.Current.Request.Cookies["blogPassword"];
          if (usernameCookie != null && passwordCookie != null)
          {
               _username = sanitize(usernameCookie.Value, clean.DB);
               password = sanitize(passwordCookie.Value, clean.DB);
          }
     }

     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"]);
          cookie(true, password);     //set cookies and sessions
     }
     else
     {
          loggedIn = false;
          if (getVariable("username", var.POST) != null && getVariable("password", var.POST) != null)
          {
               loginFailed = true;
          }
          cookie(false, null);     //remove any sessions or cookies
     }
     dr.Dispose();
}
private void cookie(bool set, string password)
{
     HttpCookie usernameCookie = new HttpCookie("blogUsername");
     HttpCookie passwordCookie = new HttpCookie("blogPassword");
     switch (set)
     {
          case true:
               //set cookies
               usernameCookie.Value = username;
               passwordCookie.Value = password;
               usernameCookie.Expires = System.DateTime.Now.AddHours(24);
               passwordCookie.Expires = System.DateTime.Now.AddHours(24);
               HttpContext.Current.Response.Cookies.Add(usernameCookie);
               HttpContext.Current.Response.Cookies.Add(passwordCookie);

               //set sessions
               Session["blogUsername"] = username;
               Session["blogPassword"] = password;
               break;
          case false:
               //set cookies to expire yesterday
               usernameCookie = HttpContext.Current.Request.Cookies["blogUsername"];
               passwordCookie = HttpContext.Current.Request.Cookies["blogPassword"];
               try
               {
                    usernameCookie.Expires = DateTime.Now.AddDays(-1);
                    HttpContext.Current.Response.Cookies.Add(usernameCookie);
               }
               catch { }
               try
               {
                    passwordCookie.Expires = DateTime.Now.AddDays(-1);
                    HttpContext.Current.Response.Cookies.Add(passwordCookie);
               }
               catch { }

               //kill sessions
               Session.Abandon();
               break;
     }
}

Let's begin partially through the authenticate() method. You can see that in the successful authenticate decision, the last thing I do is call a new method called cookie() set to true and with the password sent as the second string variable. In the login failure decision, I also call cookie() but set to false and a null in the second variable.

Next for the cookie() method, what we do is create two cookie objects, one called blogUsername and the other called blogPassword. If the first method variable (set) is true, we use the code to set usernameCookie to the username variable and passwordCookie to the password variable. Please notice that the password is already md5 hashed. We're not setting it to the plain-text password. We also set Session["blogUsername"] and Session["blogPassword"], which are session variables. Session variables are basically variables you can set on the server... they're actually small 'cookies' of a sort that expire relatively quickly. Cookies, on the other hand, are set on the client and can last an arbitrarily large amount of time. In this case, we're setting them to last 24 hours.

In the false case, I'm getting the blogUsername and blogPassword cookies, then setting them to expire yesterday. This makes the user's browser delete them. I've wrapped the statements in try/catch statements because if the cookies don't exist, this would throw an exception. I then invoke Session.Abandon() to kill the session variables.
Comments (0)
Back to our authenticate() method, I've added a few more things at the top.
private void authenticate()
{
     string _username = null, password = null;
     if (getVariable("username", var.POST) != null && getVariable("password", var.POST) != null)
     {     //check for POST vars from the login form
          _username = sanitize(getVariable("username", var.POST), clean.DB);
          password = FormsAuthentication.HashPasswordForStoringInConfigFile(getVariable("password", var.POST), "MD5");
     }
     else if (Session["blogUsername"] != null && Session["blogPassword"] != null)
     {     //check for sessions
          _username = sanitize(Session["blogUsername"].ToString(), clean.DB);
          password = sanitize(Session["blogPAssword"].ToString(), clean.DB);
     }
     else
     {     //check for cookies
          HttpCookie usernameCookie = HttpContext.Current.Request.Cookies["blogUsername"];
          HttpCookie passwordCookie = HttpContext.Current.Request.Cookies["blogPassword"];
          if (usernameCookie != null && passwordCookie != null)
          {
               _username = sanitize(usernameCookie.Value, clean.DB);
               password = sanitize(passwordCookie.Value, clean.DB);
          }
     }

You can still see where I look for the POST variables that a form submission would create. I've also added in code to check for sessions and cookies. Remember that we set our cookie password to an already md5 version, so there's no need to re-hash the password once we pull it out of the session or cookie. Similarly, since we aren't hashing it here, we're sanitizing it. The reason is that someone could have maliciously altered their cookie to include SQL injection code. In general, any time you pull a variable from outside the currently executing page, you want to sanitize it.
Comments (0)
Now when you log in, you should notice that your login continues to work as you click around the pages. So now let's make logout work and everything related to authentication will work. We already have a logout button defined that sends a GET variable called logon with a value of false. So in order to make the log off work, we can do this.
if (getVariable("logon", var.GET) == "false")
{
     cookie(false, null);
     return;
}

I stuck the above in the top of the authenticate() method. That way all my log in and log out info is centrally located. Now when you click log out, you do indeed log out. Congratulations, our authentication section of the website is complete. This section is the most important and, many times, the most complicated thing to code.

As promised, you can download all the code, graphics, css, etc at the following link in case you need to look at things more closely.

Code and Files

Next let's create the interface with which to write a blog entry.
Comments (0)