[.NET 基於角色安全性驗證] 之三:ASP.NET Forms 身份驗證

NO IMAGE

在開發過程中,我們需要做的事情包括:

1. 在 web.config 中設定 Forms 身份驗證相關引數。
2. 建立登入頁。

登入頁中的操作包括:

1. 驗證使用者名稱和密碼是否正確。
2. 建立身份驗證票證物件。
3. 將身份驗證票證物件加密成字串,寫入 Cookies。
4. 重定向到原始請求 URL。

1. 簡單演示

web.config

<?xml version=”1.0″?>
<configuration>
  <system.web>
    <compilation debug=”true”/>
    <authentication mode=”Forms”>
      <forms loginUrl=”~/logon.aspx” name=”MyAuthForm”>
        <credentials passwordFormat=”Clear”>
          <user name=”username” password=”password”/>
        </credentials>
      </forms>
    </authentication>
    <authorization>
      <deny users=”?”/>
    </authorization>
  </system.web>
</configuration>

logon.aspx

<%@ Page Language=”C#” %>
<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>

<script runat=”server”>
  protected void Button1_Click(object sender, EventArgs e)
  {
    if (FormsAuthentication.Authenticate(this.txtUsername.Text, this.txtPassword.Text))
      FormsAuthentication.RedirectFromLoginPage(this.txtUsername.Text, true);
    else
      Response.Write(“使用者名稱或密碼錯誤!”);
  }
</script>

<html xmlns=”http://www.w3.org/1999/xhtml” >
<head runat=”server”>
 <title>登入頁</title>
</head>
<body>
 <form id=”form1″ runat=”server”>
 <div>
    Username: <asp:TextBox ID=”txtUsername” runat=”server” Width=”100px” Text=”username”></asp:TextBox><br />
    Password: <asp:TextBox ID=”txtPassword” runat=”server” Width=”100px” Text=”password”></asp:TextBox><br />
    <asp:Button ID=”Button1″ runat=”server” Text=”Sign In” OnClick=”Button1_Click” />
 </div>
 </form>
</body>
</html>

2. Forms 驗證引數

如果只是某些子目錄中的頁面訪問請求需要進行身份驗證,那麼可以修改一下根路徑下的 web.config。

web.config

<?xml version=”1.0″?>
<configuration>
  <system.web>
    <compilation debug=”true”/>
    <authentication mode=”Forms”>
      <forms loginUrl=”~/logon.aspx” name=”MyAuthForm”>
        <credentials passwordFormat=”Clear”>
          <user name=”username” password=”password”/>
        </credentials>
      </forms>
    </authentication>
    <authorization>
      <allow users=”*”/>
    </authorization>
  </system.web>
</configuration>

然後在需要進行身份驗證的子目錄中建立一個新的 web.config。

<?xml version=”1.0″?>
<configuration>
  <system.web>
    <authorization>
      <deny users=”?”/>
    </authorization>
  </system.web>
</configuration>

我們還可以在根路徑下的 web.config 中指定相關引數來控制身份驗證模式。

cookieless
  定義是否使用 Cookie 以及 Cookie 的行為。
  .UseCookies
    指定無論在什麼裝置上都始終使用 Cookie。
  .UseUri
    指定從不使用 Cookie。
  .AutoDetect
    如果裝置配置檔案支援 Cookie,則指定使用 Cookie;否則不使用 Cookie。
  .UseDeviceProfile
    如果瀏覽器支援 Cookie,則指定使用 Cookie;否則不使用 Cookie。
    對於支援 Cookie 的裝置,不嘗試通過探測來確定是否已啟用 Cookie 支援。
 
defaultUrl
  定義在身份驗證之後用於重定向的預設 URL。 預設值為 “default.aspx”。
  當我們直接開啟登入頁進行登入後,該屬性就很重要了。

loginUrl
  指定如果找不到任何有效的身份驗證 Cookie,將請求重定向到的用於登入的 URL。預設值為 login.aspx。
 
name
  指定要用於身份驗證的 HTTP Cookie。如果正在一臺伺服器上執行多個應用程式並且每個應用程式都需要
  唯一的 Cookie,則必須在每個應用程式的 Web.config 檔案中配置 Cookie 名稱。預設值為 “.ASPXAUTH”。
 
path
  為應用程式發出的 Cookie 指定路徑。
  預設值是斜槓 (/),這是因為大多數瀏覽器是區分大小寫的,如果路徑大小寫不匹配,瀏覽器不會送回 Cookie。
 
timeout
  指定 Cookie 過期前逝去的時間(以整數分鐘為單位)。永續性 Cookie 不超時。預設值為 “30”(30 分鐘)。

更詳細資訊,請參考 MSDN 文件。
ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.NETDEVFX.v20.chs/dv_ASPNETgenref/html/8163b8b5-ea6c-46c8-b5a9-c4c3de31c0b3.htm

<?xml version=”1.0″?>
<configuration>
  <system.web>
    <compilation debug=”true”/>
    <authentication mode=”Forms”>
      <forms loginUrl=”~/logon.aspx” name=”MyForm” defaultUrl=”index.aspx” timeout=”10″>
        <credentials passwordFormat=”Clear”>
          <user name=”username” password=”password”/>
        </credentials>
      </forms>
    </authentication>
    <authorization>
      <allow users=”*”/>
    </authorization>
  </system.web>
</configuration>

3. 驗證方法

我們可以使用下面 4 種方法中的一種進行票證寫入和重定向操作,其實前 3 種只不過是對第 4 種方法的封裝而已。推薦使用 1、4。注意後三種方法不支援cookieless=”UseUri”。

// 1. 使用預設身份驗證票證
FormsAuthentication.RedirectFromLoginPage(“username”, true);

// 2. 使用預設身份驗證票證
FormsAuthentication.SetAuthCookie(“username”, false);
Response.Redirect(FormsAuthentication.GetRedirectUrl(“username”, false));

// 3. 使用預設身份驗證票證
Response.Cookies.Add(FormsAuthentication.GetAuthCookie(“username”, false));
Response.Redirect(FormsAuthentication.GetRedirectUrl(“username”, false));

// 4. 使用自定義身份驗證票證
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, “username”, DateTime.Now, DateTime.Now.AddMinutes(10), false, null);
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket)));
Response.Redirect(FormsAuthentication.GetRedirectUrl(“username”, false));

4. 自定義身份標識型別

MSDN 文件告訴我們,可以在 Global.asax 中通過 Authenticate 事件使用自定義 Principal、Identity 替代 GenericPrincipal、FormsIdentity。因為 Authenticate 事件在 AuthenticateRequest 事件期間引發,因此我們可以在其他模組之前建立使用者身份標識物件(FormsAuthenticationEventArgs.User)。

ms-help://MS.MSDNQTR.v80.chs/MS.MSDN.v80/MS.NETDEVFX.v20.chs/cpref12/html/T_System_Web_Security_FormsAuthenticationEventHandler.htm

class MyPrincipal : System.Security.Principal.IPrincipal
{
  // …
}

class MyIdentity : System.Security.Principal.IIdentity
{
  // …
}
  
public void FormsAuthentication_OnAuthenticate(object sender, FormsAuthenticationEventArgs args)
{
  if (FormsAuthentication.CookiesSupported)
  {
    if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
    {
      try
      {
        FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(
          Request.Cookies[FormsAuthentication.FormsCookieName].Value);
 
        args.User = new MyPrincipal(new MyIdentity (ticket), new string[0]);
      }
      catch (Exception e)
      {
        // Decrypt method failed.
      }
    }
  }
  else
  {
    throw new HttpException(“Cookieless Forms Authentication is not ”
      “supported for this application.”);
  }

}

當然,還有另外一種簡便的方法。

if (!(HttpContext.Current.User is MyPrincipal))
{
  HttpContext.Current.User = new MyPrincipal(new MyIdentity(ticket), roles);
}

只不過,你要找一個合適的時機而已。

5. FormsAuthentication

Authenticate
對照儲存在應用程式配置檔案中的憑據來驗證使用者名稱和密碼。該方法只能驗證儲存在 web.config 中的使用者名稱和密碼資訊,大多數時候我們會用自己的驗證方法替代它。

Decrypt
解密從 Cookie 中獲取的加密字串,建立 FormsAuthenticationTicket 物件。

Encrypt
加密 FormsAuthenticationTicket,返回加密後字串。

GetRedirectUrl
返回導致重定向到登入頁的原始請求 URL。GetRedirectUrl 方法返回查詢字串中使用 ReturnURL 變數名指定的 URL。例如,在 URL http://www.contoso.com/login.aspx?ReturnUrl=caller.aspx 中,GetRedirectUrl 方法返回返回 caller.aspx。如果 ReturnURL 變數不存在,GetRedirectUrl 方法將返回 DefaultUrl 屬性中的 URL。

RedirectFromLoginPage
將經過身份驗證的使用者重定向回最初請求的 URL 或 DefaultUrl 。

RedirectToLoginPage
將瀏覽器重定向到登入 URL。

RenewTicketIfOld
有條件地更新 FormsAuthenticationTicket 的發出日期和時間以及過期日期和時間。 注意該方法只是返回更新後的 FormsAuthenticationTicket 物件,並不會寫入 Cookies。

GetAuthCookie
為給定的使用者名稱建立身份驗證 Cookie,並不新增到響應的 Cookie 集合或 URL。

SetAuthCookie
為提供的使用者名稱建立一個身份驗證票證,並將其新增到響應的 Cookie 集合或 URL。

SignOut
從瀏覽器刪除 Forms 身份驗證票證。

6. 票證自定義資料應用

使用自定義票證時,我們可以新增一個 userData 引數。善加利用這個引數還是能帶了一些意想不到的好處的,諸如儲存使用者 VIP 等級編號,所擁有的許可權/角色集合等。當然 Cookie 和 URL 引數長度有限,這個自定義資料不能太長。