直播中
以前用ASP,PHP,JSP編寫網(wǎng)站代碼的時候,站點安全性總是一件頭疼的事情,雖然我們編寫了用戶登錄,注冊,驗證頁面,但是效果總是不理想。有時候我們不得不用大量的session變量來存放相關(guān)信息,處處設(shè)防。而在.NET環(huán)境下,這個問題處理起來就非常容易了。關(guān)鍵是要充分理解web.config文件。首先,介紹一下web.config文件。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<!-- 動態(tài)調(diào)試編譯
設(shè)置 compilation debug="true" 以將調(diào)試符號(.pdb 信息)
插入到編譯頁中。因為這將創(chuàng)建執(zhí)行起來
較慢的大文件,所以應(yīng)該只在調(diào)試時將該值設(shè)置為 true,而所有其他時候都設(shè)置為
false。有關(guān)更多信息,請參考有關(guān)
調(diào)試 ASP.NET 文件的文檔。
-->
<compilation defaultLanguage="vb" debug="true" />
<!-- 自定義錯誤信息
設(shè)置 customErrors mode="On" 或 "RemoteOnly" 以啟用自定義錯誤信息,或設(shè)置為 "Off" 以禁用自定義錯誤信息。
為每個要處理的錯誤添加 <error> 標記。
-->
<customErrors mode="RemoteOnly" />
<!-- 身份驗證
此節(jié)設(shè)置應(yīng)用程序的身份驗證策略。可能的模式是 \“Windows\”、
\“Forms\”、\“Passport\”和 \“None\”
-->
<authentication mode="Windows" />
<!-- 授權(quán)
此節(jié)設(shè)置應(yīng)用程序的授權(quán)策略。可以允許或拒絕用戶或角色訪問
應(yīng)用程序資源。通配符:"*" 表示任何人,"?" 表示匿名
(未授權(quán)的)用戶。
-->
<authorization>
<allow users="*" /> <!-- 允許所有用戶 -->
<!-- <allow users="[逗號分隔的用戶列表]"
roles="[逗號分隔的角色列表]"/>
<deny users="[逗號分隔的用戶列表]"
roles="[逗號分隔的角色列表]"/>
-->
</authorization>
<!-- 應(yīng)用程序級別跟蹤記錄
應(yīng)用程序級別跟蹤在應(yīng)用程序內(nèi)為每一頁啟用跟蹤日志輸出。
設(shè)置 trace enabled="true" 以啟用應(yīng)用程序跟蹤記錄。如果 pageOutput="true",則
跟蹤信息將顯示在每一頁的底部。否則,可以通過從 Web 應(yīng)用程序
根瀏覽 "trace.axd" 頁來查看
應(yīng)用程序跟蹤日志。
-->
<trace enabled="false" requestLimit="10" pageOutput="false" traceMode="SortByTime" localOnly="true" />
<!-- 會話狀態(tài)設(shè)置
默認情況下,ASP.NET 使用 cookie 標識哪些請求屬于特定的會話。
如果 cookie 不可用,則可以通過將會話標識符添加到 URL 來跟蹤會話。
若要禁用 cookie,請設(shè)置 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"
/>
<!-- 全球化
此節(jié)設(shè)置應(yīng)用程序的全球化設(shè)置。
-->
<globalization requestEncoding="utf-8" responseEncoding="utf-8" />
</system.web>
</configuration>
好了,相信看過上面的介紹以后,對web.config文件一定非常了解了吧。下面我們就切入主題。為了防止用戶沒有經(jīng)過驗證就訪問站點,我們的處理方法是當(dāng)用戶沒有通過驗證的時候點擊任何頁面將會直接跳到Login.aspx頁面,具體代碼如下:
<authentication mode="Forms">
<forms name="yourAuthCookie" loginUrl="login.aspx"
protection="All" path="/" />
</authentication>
<authorization>
<deny users="?" />
</authorization>
但是這樣會產(chǎn)生一個問題,那就是如果我的站點有一些信息是可以讓任意用戶隨意訪問的,比如站點簡介,使用說明等。如果按照上面的處理方法豈不讓用戶覺得很麻煩,呵呵,不急,在ASP.NET中自然有相應(yīng)的解決辦法。下面的代碼可以實現(xiàn)匿名用戶訪問Test.aspx頁面:
<location path="test.aspx">
<system.web>
<authorization>
<allow users="?" />
</authorization>
</system.web>
</location>
解決了上面兩個問題,相信大家心里一定有底了吧。下面就開始實現(xiàn)login.aspx頁面。利用C#和SQL Server2000,創(chuàng)建一個webform頁面,加入相應(yīng)的控件。具體代碼如下:
<%@ 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);
.
.
.
}
事件注冊好之后,自然就是編寫事件處理函數(shù)了:
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是哪里來的東東,這是我編寫的一個類,用來處理用戶登錄信息的,如果成功則把相關(guān)信息寫入session、Cookie和SQL數(shù)據(jù)庫,同時跳到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; }
}
/// <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;