A lot of us are tasked everyday to come up with ways of making our site, and other sites secure. Well if you're anything like me you don't want to have to rewrite login code 20 times a day. I'm going to show you how to make a secure site and have the login processing in a separate class. Let's get started.
In .NET to make a site secure is very simple, open up Web.Config file and look for the line that says <authentication mode="Windows" />. Delete that line and put in the following:
This now changes the way your web application will authenticate, it will no longer use NT security. Anybody trying to hit a page without authenticating first will be bounced back to the loginUrl that is specified.
Now I know a lot of you are thinking, but I have pages that aren't secure that I want the user to see. Well that is easy. After the <system.web> tag in your Web.Config file has ended put the following:
This will allow any user, authenticated or not, to access that page only, if you have a whole directory you want anyone to access just put the directory name in the path, and I mean just the name no slashes or wildcards.
Now that we have a secure site we need to make the login page that we specified in the loginUrl.
Just a quick note, I am going to be using C# in this example with a SQL database and I will supply a code sample.
Start off by creating a webform and put your form fields in there. Use web controls for your fields not HTML controls.
In this example I am actually returning a specified redirect, but if you would like to redirect them to the page that they came from you can always use:
FormsAuthentication.RedirectFromLoginPage(…)
Here is the CCommonDB class that I use to authenticate users.
CCommonDB.cs
namespace secure.Components
{
public class CCommonDB : CSql
{
public CCommonDB() : base() { }
public string AuthenticateUser(
System.Web.SessionState.HttpSessionState objSession, // Session Variable
System.Web.HttpResponse objResponse, // Response Variable
string email, // Login
string password, // Password
bool bPersist // Persist login
)
{
int nLoginID = 0;
int nLoginType = 0;
// Log the user in
Login(email, password, ref nLoginID, ref nLoginType);
if(nLoginID != 0) // Success
{
// Log the user in
System.Web.Security.FormsAuthentication.SetAuthCookie(nLoginID.ToString(), bPersist);
// Set the session varaibles
objSession["loginID"] = nLoginID.ToString();
objSession["loginType"] = nLoginType.ToString();
// Set cookie information incase they made it persistant
System.Web.HttpCookie wrapperCookie = new System.Web.HttpCookie("wrapper");
wrapperCookie.Value = objSession["wrapper"].ToString();
wrapperCookie.Expires = DateTime.Now.AddDays(30);
System.Web.HttpCookie lgnTypeCookie = new System.Web.HttpCookie("loginType");
lgnTypeCookie.Value = objSession["loginType"].ToString();
lgnTypeCookie.Expires = DateTime.Now.AddDays(30);
// Add the cookie to the response
objResponse.Cookies.Add(wrapperCookie);
objResponse.Cookies.Add(lgnTypeCookie);
return "/candidate/default.aspx";
}
case 1: // Admin Login
{
return "/admin/default.aspx";
}
case 2: // Reporting Login
{
return "/reports/default.aspx";
}
default:
{
return string.Empty;
}
}
}
else
{
return string.Empty;
}
}
/// <summary>
/// Verifies the login and password that were given
/// </summary>
/// <param name="email">the login</param>
/// <param name="password">the password</param>
/// <param name="nLoginID">returns the login id</param>
/// <param name="nLoginType">returns the login type</param>
public void Login(string email, string password, ref int nLoginID, ref int nLoginType)
{
ResetSql();
DataSet ds = new DataSet();
// Set our parameters
SqlParameter paramLogin = new SqlParameter("@username", SqlDbType.VarChar, 100);
paramLogin.Value = email;
SqlParameter paramPassword = new SqlParameter("@password", SqlDbType.VarChar, 20);
paramPassword.Value = password;
Command.CommandType = CommandType.StoredProcedure;
Command.CommandText = "glbl_Login";
Command.Parameters.Add(paramLogin);
Command.Parameters.Add(paramPassword);
Adapter.TableMappings.Add("Table", "Login");
Adapter.SelectCommand = Command;
Adapter.Fill(ds);
if(ds.Tables.Count != 0)
{
DataRow row = ds.Tables[0].Rows[0];
// Get the login id and the login type
nLoginID = Convert.ToInt32(row["Login_ID"].ToString());
nLoginType = Convert.ToInt32(row["Login_Type"].ToString());
}
else
{
nLoginID = 0;
nLoginType = 0;
}
}
}
abstract public class CSql
{
private SqlConnection sqlConnection; // Connection string
private SqlCommand sqlCommand; // Command
private SqlDataAdapter sqlDataAdapter; // Data Adapter
private DataSet sqlDataSet; // Data Set
public CSql()
{
sqlConnection = new SqlConnection(ConfigurationSettings.AppSettings["ConnectionString"]);
sqlCommand = new SqlCommand();
sqlDataAdapter = new SqlDataAdapter();
sqlDataSet = new DataSet();
sqlCommand.Connection = sqlConnection;
}
/// <summary>
/// Access to our sql command
/// </summary>
protected SqlCommand Command
{
get { return sqlCommand; }
}
/// <summary>
/// Access to our data adapter
/// </summary>
protected SqlDataAdapter Adapter
{
get { return sqlDataAdapter; }
}
/// <summary>
/// Makes sure that everything is clear and ready for a new query
/// </summary>
protected void ResetSql()
{
if(sqlCommand != null)
{
sqlCommand = new SqlCommand();
sqlCommand.Connection = sqlConnection;
}
if(sqlDataAdapter != null)
sqlDataAdapter = new SqlDataAdapter();
if(sqlDataSet != null)
sqlDataSet = new DataSet();
}
/// <summary>
/// Runs our command and returns the dataset
/// </summary>
/// <returns>the data set</returns>
protected DataSet RunQuery()
{
sqlDataAdapter.SelectCommand = Command;
sqlConnection.Open();
sqlConnection.Close();
sqlDataAdapter.Fill(sqlDataSet);
return sqlDataSet;
}
}
}
I have two classes here, a base class for the common sql functions that most of use normally do and then a class that inherits from that class to separate the code.
When you look at the code you may ask why do you pass the session variable and response variable into the function, well if you have ever tried to access the Session or Response variable from a separate cs class you always get an error saying that you need reference to the object, and in this case you can just pass the objects in and out easily and quickly without having to try to create your own instance of the Session or Response.
If you have questions please feel free to write me at ruts@datausa.com and I'll answer them the best I can.