以前用ASP,PHP,JSP編寫網站代碼的時候,網站安全性總是一件頭疼的事情,雖然我們編寫了使用者登入,註冊,驗證頁面,但是效果總是不理想。有時候我們不得不用大量的session變數來存放相關資訊,處處設防。而在.NET環境下,這個問題處理起來就非常容易了。關鍵是要充分理解web.config檔案。首先,介紹一下web.config檔案。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<!-- 動態調試編譯
設定 compilation debug="true" 以將偵錯符號(.pdb 資訊)
插入到編譯頁中。因為這將建立執行起來
較慢的大檔案,所以應該只在調試時將該值設定為 true,而所有其他時候都設定為
false。有關更多資訊,請參考有關
調試 ASP.NET 檔案的文檔。
-->
<compilation defaultLanguage="vb" debug="true" />
<!-- 自訂錯誤資訊
設定 customErrors mode="On" 或 "RemoteOnly" 以啟用自訂錯誤資訊,或設定為 "Off" 以禁用自訂錯誤資訊。
為每個要處理的錯誤添加 <error> 標記。
-->
<customErrors mode="RemoteOnly" />
<!-- 身分識別驗證
此節設定應用程式的身分識別驗證策略。可能的模式是 \“Windows\”、
\“Forms\”、\“Passport\”和 \“None\”
-->
<authentication mode="Windows" />
<!-- 授權
此節設定應用程式的授權策略。可以允許或拒絕使用者或角色訪問
應用程式資源。萬用字元:"*" 表示任何人,"?" 表示匿名
(未授權的)使用者。
-->
<authorization>
<allow users="*" /> <!-- 允許所有使用者 -->
<!-- <allow users="[逗號分隔的使用者列表]"
roles="[逗號分隔的角色列表]"/>
<deny users="[逗號分隔的使用者列表]"
roles="[逗號分隔的角色列表]"/>
-->
</authorization>
<!-- 應用程式層級追蹤記錄
應用程式層級跟蹤在應用程式內為每一頁啟用追蹤記錄檔輸出。
設定 trace enabled="true" 以啟用應用程式追蹤記錄。如果 pageOutput="true",則
跟蹤資訊將顯示在每一頁的底部。否則,可以通過從 Web 應用程式
根瀏覽 "trace.axd" 頁來查看
應用程式追蹤記錄檔。
-->
<trace enabled="false" requestLimit="10" pageOutput="false" traceMode="SortByTime" localOnly="true" />
<!-- 工作階段狀態設定
預設情況下,ASP.NET 使用 cookie 標識哪些請求屬於特定的會話。
如果 cookie 不可用,則可以通過將工作階段識別項添加到 URL 來跟蹤會話。
若要禁用 cookie,請設定 sessionState cookieless="true"。
-->
<sessionState
mode="InProc"
stateConnectionString="tcpip=127.0.0.1:42424"
sqlConnectionString="data source=127.0.0.1;user id=sa;password="
cookieless="false"
timeout="20"
/>
<!-- 全球化
此節設定應用程式的全球化設定。
-->
<globalization requestEncoding="utf-8" responseEncoding="utf-8" />
</system.web>
</configuration>
好了,相信看過上面的介紹以後,對web.config檔案一定非常瞭解了吧。下面我們就切入主題。為了防止使用者沒有經過驗證就訪問網站,我們的處理方法是當使用者沒有通過驗證的時候點擊任何頁面將會直接跳到Login.aspx頁面,具體代碼如下:
<authentication mode="Forms">
<forms name="yourAuthCookie" loginUrl="login.aspx"
protection="All" path="/" />
</authentication>
<authorization>
<deny users="?" />
</authorization>
但是這樣會產生一個問題,那就是如果我的網站有一些資訊是可以讓任意使用者隨意訪問的,比如網站簡介,使用說明等。如果按照上面的處理方法豈不讓使用者覺得很麻煩,呵呵,不急,在ASP.NET中自然有相應的解決辦法。下面的代碼可以實現匿名使用者存取Test.aspx頁面:
<location path="test.aspx">
<system.web>
<authorization>
<allow users="?" />
</authorization>
</system.web>
</location>
解決了上面兩個問題,相信大家心裡一定有底了吧。下面就開始實現login.aspx頁面。利用C#和SQL Server2000,建立一個webform頁面,加入相應的控制項。具體代碼如下:
<%@ Page language="c#" Codebehind="login.aspx.cs"
AutoEventWireup="false" Inherits="secure.login" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>Secure Site</title>
<meta content="Microsoft Visual Studio 7.0" name="GENERATOR">
<meta content="C#" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5"
name="vs_targetSchema">
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="login" method="post" runat="server">
<table cellSpacing="0" cellPadding="0" border="0">
<tr>
<td vAlign="top" align="left">
<asp:label id="Message" Runat="server" ForeColor="#ff0000">
</asp:label>
</td>
</tr>
<tr>
<td vAlign="top" align="left">
<b>E-mail:</b>
</td>
</tr>
<tr>
<td vAlign="top" align="left">
<asp:textbox id="username" Runat="server" Width="120">
</asp:textbox>
</td>
</tr>
<tr>
<td vAlign="top" align="left">
<b>Password:</b>
</td>
</tr>
<tr>
<td vAlign="top" align="left">
<asp:textbox id="password" Runat="server"
Width="120" TextMode="Password">
</asp:textbox>
</td>
</tr>
<tr>
<td vAlign="top" align="left">
<asp:checkbox id="saveLogin" Runat="server"
Text="<b>Save my login</b>">
</asp:checkbox>
</td>
</tr>
<tr>
<td vAlign="top" align="right">
<asp:imagebutton id="btnLogin" Runat="server"
ImageUrl="/images/w2k/login/btnLogin.gif">
</asp:imagebutton>
</td>
</tr>
</table>
</form>
</body>
</HTML>
介面做好之後,就開始編寫提交按鈕事件,首先需要註冊該事件,代碼如下:
private void InitializeComponent()
{
this.btnLogin.Click += new System.Web.UI.ImageClickEventHandler(this.btnLogin_Click);
.
.
.
}
事件註冊好之後,自然就是編寫事件處理函數了:
private void btnLogin_Click(object sender, System.Web.UI.ImageClickEventArgs e)
{
CCommonDB sql = new CCommonDB();
string redirect = "";
if((redirect = sql.AuthenticateUser(this.Session, this.Response,
username.Text, password.Text, saveLogin.Checked)) != string.Empty)
{
// Redirect the user
Response.Redirect(redirect);
}
else
{
Message.Text = "Login Failed!";
}
}
讀者看完上面的代碼之後一定想問CCommonDB是哪裡來的東東,這是我編寫的一個類,用來處理使用者登入資訊的,如果成功則把相關資訊寫入session、Cookie和SQL資料庫,同時跳到default.aspx頁面。具體如下:
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; }
} ( 負責編輯:kaso )
/// <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;
}
}
}