[.NET 基於角色安全性驗證] 之五:跨應用程序進行 Forms 身份驗證
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>
<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();
}
}
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()));
}
{
Response.Write(HttpUtility.HtmlEncode(new MachineKey().GenerateKey()));
}
最後更新:2017-04-02 00:06:28