ASP.NET實現匿名訪問控制

ASP.NET實現匿名訪問控制

通過學習我掌握了兩種控制方法,實現了對於網站的匿名訪問控制,一個是通過IIS實現,另一個是通過ASP.NET實現。個人感覺兩種基本上可以實現的功能沒有什麼差別,不過通過ASP.NET實現的更易於管理和維護。

對於通過IIS的實現都比較清楚,可以對文件夾或單個文件(頁面)設置訪問權限,IIS提供了“目錄安全性”和“文件安全性”的設置方法。並可以通過直接設置不同訪問人的權限。其中就提供了匿名訪問的控制方法,這裏不再細說。

 

ASP.NET控制方法:

首先介紹例子實現的效果,一個網站登陸以後可以將用戶信息保存在一個cookie中,並標識用戶是通過身份驗證的,在訪問其他頁面的時候直接對用戶的身份是否通過驗證進行判斷,如果通過即可繼續訪問頁面,如果是一個未通過驗證的匿名訪問用戶(即未登錄用戶)則將跳轉到登陸頁面提示用戶登錄。設置其中一個用戶註冊頁面爲可以匿名訪問,因爲業務邏輯上只有允許註冊才能登陸。

在登陸頁面還是先對用戶的用戶名和密碼進行驗證,至於使用與數據庫比對的方法還是到AD中驗證等都可以,然後通過以下的方法將當前用戶在cookie中標識爲通過驗證的用戶,並跳轉到用戶跳轉到登陸頁之前請求的頁面。

FormsAuthentication.RedirectFromLoginPage(userName,createPersistentCookie);

FormsAuthentication.RedirectFromLoginPage(UserEmail.Value, PersistCookie.Checked);

在用戶直接請求的頁面上我們使用如下的方法來驗證用戶。

Context.User.Identity.IsAuthenticated

Context:獲取與該頁關聯的 System.Web.HttpContext 對象

User:爲當前 HTTP 請求獲取或設置安全信息

Identity:獲取當前用戶的標識

IsAuthenticated:獲取一個bool值,該值指示是否驗證了用戶

 

然後我們在Web.config中進行安全設置。

<authentication mode="Forms">

    <forms loginUrl="Login.aspx"></forms>

</authentication>

"Forms" 您爲用戶提供一個輸入憑據的自定義窗體(Web 頁),然後在您的應用程序中驗證他們的身份。用戶憑據標記存儲在 Cookie 中。

    <authorization>

        <deny users="?" />

    </authorization>

deny表示禁止,users="?"表示匿名用戶

  <location path="NewUser.aspx">

    <system.web>

        <authorization>

            <allow users="*" />

        </authorization>

    </system.web>

  </location>

表示新用戶註冊頁面NewUser.aspx,可以允許任何人訪問。

這樣就實現了對於匿名用戶的訪問控制。

對於機密目錄,我們可以參照以下的說明:

我們設置機密目錄(也就是"安全目錄",特定的使用者如管理員纔有權限訪問的目錄)。首先看看你的Web應用程序根目錄下是否有 Web.config 這個文件,如果沒有就創建一個。你也可以在你的子目錄中創建 Web.config 文件,當然,這個 Web.config 文件是有限制的(一些參數它不可以設置)。要實現安全認證,在 Web應用程序根目錄下的 Web.config 文件中找到 <system.web> 節點下的

 程序代碼
<authentication mode="Windows" />,把它修改爲

<authentication mode="Forms">
<forms name="AMUHOUSE.ASPXAUTH"
loginUrl="Login.aspx"
protection="All"
path="./" />
</authentication>
<authorization>
<allow users="*"/>
</authorization>

上面的 name="AMUHOUSE.ASPXAUTH" 中,AMUHOUSE.ASPXAUTH 這個名稱是任意的。要控制用戶或者用戶組的權限,我們可以有兩種方法,一是配置在應用程序根目錄下的 Web.config 文件,二是在機密目錄下創建一個獨立的 Web.config 文件。(後者也許會比較好。)如果是前者,這個Web.config 就應該包含有下面的內容(或者類似的內容):


 程序代碼
<configuration>
  <system.web>
    <authentication mode="Forms">
      <forms name=" AMUHOUSE.ASPXAUTH"
        loginUrl="login.aspx"
        protection="All"
        path="/"/>
    </authentication>
    <authorization>
      <allow users="*"/>
    </authorization>
  </system.web>
<location path="./Admin">
  <system.web>
    <authorization>
      <!-- 注意!下面幾行的順序和大小寫是非常重要的! -->
      <allow roles="Administrator"/>
      <deny users="*"/>
    </authorization>
  </system.web>
</location>
<location path="./User">
  <system.web>
    <authorization>
      <!-- 注意!下面幾行的順序和大小寫是非常重要的! -->
      <allow roles="User"/>
      <deny users="*"/>
    </authorization>
  </system.web>
</location>
</configuration>


爲了使Web應用程序的目錄之前不互相依賴,可以比較方便的改名或者移動,可以選擇在每一個安全子目錄下配置單獨的 Web.config 文件。它只需要配置 <authorization/>節點,如下:


 程序代碼
<configuration>
<system.web>
<authorization>
<!-- 注意!下面幾行的順序和大小寫是非常重要的! -->
<allow roles="Administrator"/>
<deny users="*"/>
</authorization>
</system.web>
</configuration>


需要再次提醒的是,上面的角色 roles 是大小寫敏感的,爲了方便,你也可以把上面修改爲:
<allow roles="Administrator,administrator" />
如果你想允許或者禁止多個角色對這個目錄的訪問,可以用逗號隔開,如:
<allow roles="Administrator,Member,User" />
<deny users="*" />

至此,我們已經爲網站配置了基於角色的安全認證機制了。你可以先編譯你的程序,然後嘗試訪問一個機密目錄,例如 http://localhost/RolebasedAuth/Admin ,這時候你就會被轉向到用戶登錄頁面。如果你登錄成功,並且你的角色對這個目錄有訪問權限,你就重新回到這個目錄下。可能會有用戶(或入侵者)企圖進入機密目錄,我們可以使用一個 Session 來存儲用戶登錄的次數,超過一定次數就不讓用戶登錄,並且顯示"系統拒絕了你的登錄請求!"。

下面,我們討論如何根據用戶角色讓Web控件顯示不同內容。

有時候根據用戶的角色來顯示內容比較好,因爲你可能不想爲那麼多不同的角色(用戶羣組)製作一大堆有許多重複內容的頁面。這樣的網站,各種用戶帳戶可以並存,付費的用戶帳戶能夠訪問附加的付費內容。另一個例子是一個頁面將顯示一個 "進入後臺管理" 按鈕鏈接到後臺管理頁面如果當前用戶是 "Administrator"(高級管理員)角色。我們現在就實現這個頁面。
我們上面用到的 GenericPrincipal 類實現了 IPincipal 接口,這個接口有一個方法名叫做 IsInRole(),它的參數是一個字符串,這個字符串就是要驗證的用戶角色。如果我們要顯示內容給角色是 "Administrator"的已登錄用戶,我們可以在 Page_Load 中添加下面代碼:

 程序代碼
if (User.IsInRole("Administrator"))
AdminLink.Visible = true;

整個的頁面代碼如下(爲了簡便,把後臺代碼也寫在aspx頁面):


 程序代碼
<html>
<head>
<title>歡迎您!</title>
<script runat="server">
protected void Page_Load(Object sender, EventArgs e)
{
if (User.IsInRole("Administrator"))
AdminLink.Visible = true;
else
AdminLink.Visible = false;
}
</script>
</head>
<body>
<h2>歡迎!</h2>
<p>歡迎來到阿木小屋 http://amuhouse.com/ ^_^</p>
<asp:HyperLink id="AdminLink" runat="server"
Text="管理首頁" NavigateUrl="./Admin"/>
</body>
</html>

這樣,鏈接到 Admin 目錄的HyperLink 控件只會顯示給角色是 Administrator 的用戶。你也可以根據爲未登錄用戶提供一個鏈接到登錄頁面,如:


 程序代碼
protected void Page_Load(object sender, System.EventArgs e)
{

if (User.IsInRole("Administrator"))
{
AdminLink.Text = "管理員請進";
AdminLink.NavigateUrl="./Admin";
}
else if(User.IsInRole("User"))
{
AdminLink.Text = "註冊用戶請進";
AdminLink.NavigateUrl="./User";

}
else
{
AdminLink.Text = "請登錄";
AdminLink.NavigateUrl="Login.aspx?ReturnUrl=" + Request.Path;
}

}


這裏,我們通過設置叫做ReturnUrl的 QueryString 變量,可以使用戶登錄成功後返回到當前的這個頁面.

 下面是一個簡單例子:

Default.aspx:
<%@ Import Namespace="System.Web.Security "%>

<html>


  <script language="C#" runat=server>

    void Page_Load(Object Src, EventArgs E ) {

      Welcome.Text = "Hello, " + User.Identity.Name;
    }

    void Signout_Click(Object sender, EventArgs E) {

      FormsAuthentication.SignOut();
      Response.Redirect("login.aspx");
    }

  </script>

  <body>

    <h3><font face="宋體">使用 Cookie 身份驗證</font></h3>

    <form runat=server>

      <h3><asp:label id="Welcome" runat=server/></h3>

      <asp:button text="註銷" OnClick="Signout_Click" runat=server/>

    </form>

  </body>

</html>

login.aspx: 
<%@ Import Namespace="System.Web.Security "%>


<html>


  <script language="C#" runat=server>

    void Login_Click(Object sender, EventArgs E) {
      if (((UserEmail.Value == "[email protected]") && (UserPass.Value == "password")) || ((UserEmail.Value == "[email protected]") && (UserPass.Value == "password"))) {
        FormsAuthentication.RedirectFromLoginPage(UserEmail.Value, PersistCookie.Checked);
      }
      else {
        Msg.Text = "憑據無效:請再試一次";
      }
    }

  </script>

  <body>

    <form runat=server>

      <h3><font face="宋體">登錄頁</font></h3>

      <table>
        <tr>
          <td>電子郵件:</td>
          <td><input id="UserEmail" type="text" runat=server/></td>
          <td><ASP:RequiredFieldValidator ControlToValidate="UserEmail" Display="Static" ErrorMessage="*" runat=server/></td>
        </tr>
        <tr>
          <td>密碼:</td>
          <td><input id="UserPass" type=password runat=server/></td>
          <td><ASP:RequiredFieldValidator ControlToValidate="UserPass" Display="Static" ErrorMessage="*" runat=server/></td>
        </tr>
        <tr>
          <td>持久的 Cookie:</td>
          <td><ASP:CheckBox id=PersistCookie runat="server"/> </td>
          <td></td>
        </tr>
      </table>

      <asp:button text="登錄" OnClick="Login_Click" runat=server/>

      <p>

      <asp:Label id="Msg" ForeColor="red" Font-Name="Verdana" Font-Size="10" runat=server/>

    </form>
  </body>

</html>
 
web.config:
<configuration>
  <system.web>
      <authentication mode="Forms">
        <forms name=".ASPXUSERDEMO" loginUrl="login.aspx" protection="All" timeout="60"/>
      </authentication>
      <authorization>
        <deny users="[email protected]" />
        <deny users="?" />
      </authorization>
    <globalization requestEncoding="UTF-8" responseEncoding="UTF-8"/>
  </system.web>
</configuration>
 
 
這是從MSDN上摘抄整理而來的,結合我自己的經驗之談。
  
  我看了有很多朋友都在嘗試寫出帶有登陸這樣功能的網站,其方法幾乎都是驗證用戶的登陸合法,然後發送一個表示驗證的Cookie,或者在Session中保存信息以便於追蹤接下來的訪問授權,其實,這些細節化的操作,.NET都提供了一種非常有效的解決辦法,能使你從繁瑣的安全驗證上解脫出來,而且,儘管你可能很小心地定義那些頁面不能被沒有權限的人訪問,然而還有可能出現一些無法被檢查出來的漏洞讓他們跳過安全驗證
  
  
  好,廢話少說,本文將介紹如下內容:
  1、關於登陸驗證和授權
  2、使用Forms驗證模式
  3、授權資源的訪問
  4、基於角色的授權
  
  
  1、關於登陸驗證和授權
   很多網站都有登陸對話框,讓事先已經註冊的用戶驗證,以便爲他們提供個性化的服務等。可以把這個過程看作是兩件事情的發生:驗證和授權!登陸的作用是驗證請求登陸的用戶是否合法,而授權則是驗證合法的用戶在請求資源時,根據他們的權限決定是訪問還是拒絕。
   以上這種網站本身提供對話框的作法在.NET中被稱之爲Forms驗證模式,接下來將會講述這種驗證模式。在以前ASP陳序員或者其他程序員,要想保存合法用戶的驗證,在以後的訪問授權中使用,不得不使用寫Cookie或者將信息保存在Session中的方法,而在需要授權的頁面加載前添加一堆繁瑣的代碼來驗證制定的用戶是否具有訪問權限否則的話就不能顯示頁面的內容,最惱火的是在授權頁面上添加這些代碼讓人覺得重複和繁瑣,而且可能不是最安全的,有一些比較隱蔽的方式可能會輕易繞過這種驗證,因此程序員將來要做的很多事情就是再修改代碼已堵住在運行過程中才發現的漏洞。在.NET的System.Web.Security中提供了一些網站安全方面的解決方案,儘管驗證用戶合法和授權的基本思路沒有變化,但是授權的工作幾乎已經交給.NET框架了,我們些代碼之需要自己驗證用戶合法,並且告訴框架這個用戶合法即可。
  
  2、使用Forms驗證模式
   要使用啓用Forms驗證模式,請在網站根目錄下的web.config文件中添加如下配置:(注意區分大小寫)
  
  <configuration>
   <system.web>
   <authentication mode="Forms" />
   </system.web>
  </configuration>
  
   這將告訴.NET,你的網站使用Forms驗證模式,.NET將不參與驗證用戶的工作,而是將這個工作交給你完成,你必須自己編寫一些代碼來驗證用戶合法,並且報告給.NET用戶是合法的。.NET將會發送一個驗證Cookie到用戶,隨後的訪問中,.NET以此Cookie爲依據,來執行授權的操作。
  
   例如我們在login.ASPx界面中放置兩個接受輸入的文本框txtUserName和txtPassword,在數據庫中,保存了用戶名UserName和密碼UserPassword,使用btnLogin按鈕的Click事件來驗證用戶:
  
  private void btnLogin_Click(object sender, EventArgs e)
  {
   string sql = "SELECT userid FROM Users WHERE UserName = '" + txtUserName.Text.Replace("'","_") + "' AND UserPassword = '" + System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(txtPassword.Text, "md5") + "'";
   //使用上面類似的SQL語句向數據庫執行查詢,如果用戶是合法的,將會返回數據。
   if (...) //根據條件判定用戶是合法的
   {
   //下面的語句告訴.NET發送一個驗證Cookie給用戶:
   System.Web.Security.FormsAuthentication.SetAuthCookie(userid, false)
   Response.Redirect("afterlogin.ASPx"); //定位到登陸後頁面
   }
   else
   {
   //用戶不合法,提示錯誤信息
   }
  }
  
  以上代碼中,
  txtUserName.Text.Replace("'","_")將用戶輸入的文本中單引號替換爲下劃線,以防止SQL注入攻擊。
  System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(txtPassword.Text, "md5")方法將txtPassword.Text轉換爲MD5散列值,注意,在用戶註冊的時候,同樣使用此方法將其輸入的註冊密碼轉換爲散列值存儲在數據庫中,這裏將用戶輸入的散列值進行對比以決定是否合法用戶。任何時候不要將敏感的文本信息以明文方式存放在數據庫中。通過MD5加密,即便此密文被截獲,攻擊者仍無法獲得真實的密碼。
  
  當確認用戶驗證是合法的,則調用System.Web.Security.FormsAuthentication.SetAuthCookie(userid, false)方法,發送驗證Cookie,此方法傳遞兩個參數,一個是代表用戶的標示,一般來說,在接下來確認用戶唯一身份的就是從數據庫中獲得的userid。第二個參數告訴.NET是否寫入持續的Cookie,如果爲true,則Cookie將被持續,下次用戶再次訪問時,Cookie仍存在(相當於記住用戶,可以提供這樣的複選框讓用戶來決定是否持續Cookie)。發送了Cookie後,即可調用跳轉語句跳轉到指定地方。
  
  另外還有一個方法:Web.Security.FormsAuthentication.RedirectFromLoginPage(string UserName, bool);將發送Cookie,並且根據傳遞的ReturnUrl參數來跳轉到指定的頁面(相當於將上面的兩個步驟合爲一步)。因此login.ASPx隱含可以傳遞ReturnUrl,如果沒有這個參數,這個方法將用戶跳轉到Default.ASPx頁。
  
  3、授權資源的訪問
   一旦驗證了用戶合法,接下來要做的事就是對於用戶請求的資源,授權他們是否能夠訪問。重新回到web.config文件中,在網站的任何目錄中都可以使用web.config,他們的設置是傳遞繼承的。
   例如在users目錄中存放的均是當用戶登錄後才能訪問的頁面,則在這個目錄中創建一個web.config文件,內容如下:
  
  <?xml version="1.0" encoding="utf-8" ?>
  <configuration>
   <system.web>
   <!-- 授權
   此節設置應用程序的授權策略。可以允許或拒絕不同的用戶或角色訪問
   應用程序資源。通配符: "*" 表示任何人,"?" 表示匿名
   (未經身份驗證的)用戶。
   -->
   <authorization>
   <deny users="?" />
   </authorization>
   </system.web>
  </configuration>
  
  上述內容中deny users="?" 將告訴.NET,此目錄拒絕匿名用戶的訪問,也就是沒有驗證的用戶。當用戶試圖請求此目錄中的資源,將會被重新定向到login.ASPx頁面,要求登陸。沒有登陸的情況下是無法訪問的。
  
  上述僅對目錄進行定義,程序員不用在頁面上添加任何代碼,即可完整地實現了授權方案。
  當然,這種僅針對目錄的授權配置可能有時候又會缺乏靈活,因此,.NET也提供location配置節,可以對指定的資源定義授權:
  <configuration>
   <location path="userabc.aspx">
   <system.web>
   <authorization>
   <allow users="a,b,c" />
   </authorization>
   </system.web>
   </location>
  </configuration>
  
  其中path是資源相對路徑。
  
  如果這還不夠靈活的話,.NET也提供了在代碼中使用的方法,ASP.NET頁全局隱含了一個只讀的User對象,通過獲取User.Identity.IsAuthenticated屬性,可探知用戶是否驗證(即是否登陸),User.Identity.Name屬性可以獲得用戶的Name,即在驗證時的SetAuthCookie方法中傳遞的userid。
  
  4、基於角色的授權
   上面我們講述的用戶驗證,只可能有兩種情況,要麼用戶通過驗證,可以授權訪問資源,要麼用戶沒有通過驗證,不能訪問需要授權的資源。但是即便是驗證通過的用戶,可能他們所持用的權限還需要再進一步區分。例如普通用戶和管理員同樣是需要驗證通過的,但是普通用戶顯然不能夠訪問管理頁面,而管理員可以。面對這種情況,.NET可以使用基於角色的授權模型。
   其基本原理是,一旦用戶驗證合法,他們就被分配角色,用戶可以使一個或者若干和角色,而資源的授權面向角色,這樣,針對不同的角色,就可以授予不同的權限,沒有某種角色類型的用戶試圖訪問需要這種角色的資源將會被拒絕。
   當網站開始接受用戶請求時,就伴隨着驗證,將激發Application_AuthenticateRequest事件,在Global.asax文件中寫代碼以響應此事件。角色的分配工作就需要再這裏進行。
  
  public void Application_AuthenticateRequest(object sender, EventArgs e)
  {
   if (this.Request.IsAuthenticated)
   {
   //這裏簡化了操作,可以從數據庫中獲得角色信息用以構造rolesStrArr數組。作爲示例,我們爲除了a之外的用戶分配了管理員角色
   string[] rolesStrArr;
   if (this.Context.User.Identity.Name == "a")
   {
   rolesStrArr = new string[]{"普通用戶"};
   }
   else
   {
   rolesStrArr = new string[]{"普通用戶","管理員"};
   }
   this.Context.User = new System.Security.Principal.GenericPrincipal(this.User.Identity, rolesStrArr);
   }
  }
  
  以上代碼清晰明瞭,因此不再贅述。雖然在全局性有User對象,但是隻有Context上下文中的User對象是可以寫入的,我們調用System.Security.Principal.GenericPrincipal方法,在原有User對象的基礎上爲其加入角色。角色列表示一個字符串數組。
  
   一旦用戶被授予訪問角色之後,在web.config中就可以配置針對不同角色的訪問。例如在管理員admin目錄內
  
  <configuration>
   <location path="userabc.aspx">
   <system.web>
   <authorization>
   <allow roles="管理員" />
   <deny users="*" />
   </authorization>
   </system.web>
   </location>
  </configuration>
  
  上述配置只允許管理員角色才能被授權。資源默認是任何人都訪問的,所以要在下面再添加<deny users="*" />表示對任何用戶拒絕。
  
  注意,無論對角色或者對用戶指定資源的訪問,如果對於多個角色或者讀個資源,他們之間使用半角逗號隔開。同樣,也可以使用上面講到的方法,對指定的資源進行配置而不是對整個目錄。
  
  全局的User對象提供了一個方法IsInRole(string RoleName)方法用來在代碼中檢測用戶是否擁有某種角色。如果他擁有這種角色,將返回true。
  
  
  後記
   .NET提供了完整的安全方面的解決方案,相對於ASP,這是激動人心的一個新特性。只是很多人可能並不能夠熟練地運用,而且最痛心的是,很多書籍上甚至並沒有這方面的任何描述,甚至連概念都沒有。這就讓人很懷疑編者的水平了。
   首先,還是要在不斷的實踐過程中去了解和體會.NET,其實最好的老師應當是MSDN,到論壇來發帖的用戶,我都儘量建議去查閱MSDN的資料,MSDN除了教給你怎麼寫代碼,其實他教給你的還有非常優秀的思想和整體概念。只要學會使用,沒有這些書也可以。從寫第一行代碼到現在,除了一本啓蒙書,其他的資源都是MSDN或者網上找的,還有就是在每次做項目中的心得。儘管現在看來,啓蒙書中也沒有非常全面地講述這些東西。
  
   好了,希望大家看到會有所收穫。限於我的水平,錯誤難免,歡迎指正!
發佈了0 篇原創文章 · 獲贊 1 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章