[.NET 基於角色安全性驗證] 之五:跨應用程式進行 Forms 身份驗證

NO IMAGE

ASP.NET 支援在分散式環境中(跨單個伺服器上的多個應用程式或在網路場中)進行 Forms 身份驗證。如果啟用了跨多個 ASP.NET 應用程式的 Forms 身份驗證,則當使用者在應用程式之間切換時,不需要對他們重新進行身份驗證。

要配置跨應用程式的 Forms 身份驗證,請在 forms 和 machineKey 配置節中設定若干屬性,以便值對於參與共享 Forms 身份驗證的所有應用程式都是相同的。

下面的示例演示了 Web.config 檔案的 Authentication 節。除非另行說明,否則 name、protection、path、validationKey 和 decryptionKey 屬性必須在所有應用程式中都完全相同。同樣,用於 Cookie 資料的加密和驗證金鑰以及加密方案也必須完全相同。如果設定不匹配,則不能共享 Cookie。

web.config

<configuration>
  <system.web>
    <authentication mode=”Forms” >
      <!– The name, protection, and path attributes must match
      exactly in each Web.config file. –>
      <forms loginUrl=”login.aspx”
        name=”.ASPXFORMSAUTH”
        protection=”All”
        path=”/”
        timeout=”30″ />
    </authentication>

    <!– Validation and decryption keys must exactly match and cannot
    be set to “AutoGenerate”. The validation algorithm must also
    be the same. –>
    <machineKey
      validationKey=”C50B3C89CB21F4…BE”
      decryptionKey=”8A9BE8FD67AF6979E7D20198CFEA50DD3D3799C77AF2B72F”
      validation=”SHA1″ />
  </system.web>
</configuration>

發出 Cookie 之後,將根據 Cookie 自身中的 Expires 值跟蹤 Cookie 的到期時間。這意味著如果兩個應用程式具有不同的 Timeout 屬性,則將在 Cookie 的整個生存期中保留最初發出每個 Cookie 時設定的到期日期和時間。當更新 Cookie 時,Cookie 的原始到期時間用於計算新到期時間。使用配置 Timeout 值的唯一時間就是最初建立 Cookie 的時間。

—————————————————–

補充

按照上述操作,我們就可以在單個或多個伺服器的網路場中實現 “跨應用程式進行 Forms 身份驗證”,這個有點 “單點登入(SSO, Single Sign On)” 的意思,不過有幾點還是要注意一下。

1. 如果使用新開啟的瀏覽器窗體開啟另外的應用程式網站,則必須建立持久 Cookie (跨瀏覽器會話儲存 Cookie) 時,才能在多個應用程式中共享登入資訊。
(“新開啟的瀏覽器窗體” 這話有點拗口,也就說這個窗體不是原瀏覽器彈出的,而是我們使用快捷方式新開啟的程序。)

FormsAuthentication.RedirectFromLoginPage(“username”, true);

2. MachineKey 建立方法。

using System.Text;
using System.Security.Cryptography;

public class MachineKey
{
  const int validationKeyLength = 64;
  const int decryptionKeyLength = 24;
  private RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();

  public string GenerateKey()
  {
    return string.Format(“<machineKey validationKey=/”{0}/”/r/ndecryptionKey=/”{1}/”/r/nvalidation=/”SHA1/”/>”,
      BytesToHex(GenerateKeyBytes(validationKeyLength)), BytesToHex(GenerateKeyBytes(decryptionKeyLength)));
  }

  private byte[] GenerateKeyBytes(int cb)
  {
    byte[] rndData = new byte[cb];
    rng.GetBytes(rndData);
    return rndData;
  }

  private string BytesToHex(byte[] key)
  {
    StringBuilder sb = new StringBuilder();
    
    for (int i = 0; i < key.Length; i)
    {
      sb.Append(String.Format(“{0:X2}”, key[i]));
    }

    return sb.ToString();
  }
}

使用方法

protected void Page_Load(object sender, EventArgs e)
{
  Response.Write(HttpUtility.HtmlEncode(new MachineKey().GenerateKey()));
}