ASP.NET 安全認證(三): 用Form 表單認證實現單點登入

來源:互聯網
上載者:User
asp.net|安全

“等了好久終於等到今天,寫了好久終於就快完結,但是網友的反應卻讓我有一些的傷心。盼了好久終於盼到今天,忍了好久終於把此文撰寫,那些受冷落的無奈早就無所謂,累也不說累”(歌詞《今天》新演繹)。看著人家的 Blog 文章的評論是一條接一條,再瞧瞧自己:“無人問津呐,真…無…奈……唉,沒人理我,還是回家吧。”“哎,還沒開始寫,怎麼就走了?回去幹什麼呢?”回去寫作業去啊,上回交待的課外作業你做了沒?(註:http://blog.csdn.net/cityhunter172/archive/2005/11/13/528463.aspx 在第二部分第六節布置的課外作業:此項目有兩部門使用,其中每個部門分別都有些特定的頁面僅供本部門使用者瀏覽使用,請問該如何使用 Web.config 達到效果?)

不知有多少人做了作業,其實答案並不難。只需要在驗證使用者名稱與密碼後,取得該使用者的部門名稱或部門代碼,把它作為判斷的依據就行了。最好不要用部門的數字ID,那樣不利於以後的維護。

有一個秘密,一般人我不告訴他。Web.config 中的 <location> 節點的path 屬性可以是一張具體頁面的相對 URL 路徑,如下:<location path ="ManageSys/Auditing.aspx">

好了,接下來就要揭開“比根目錄Web.config 的作用範圍還大的設定檔”之謎啦,它就是藏匿在 Windows 系統目錄下,支配整個 .Net Framework 配置的傳說中的Machine.config !!下面請大家以熱烈的掌聲,歡迎我們這位神秘俠客的閃亮登場……

九、  Machine.config

Machine.config ,性別不詳,年齡未知,家庭出身:XML。深藏於“雲深不知處”的作業系統目錄下的某某地方(註:C:\WINDOWS【或 WINNT 】\Microsoft.NET\Framework\v1.1.4322【或 v1.0.3705 】\CONFIG),控制著“更上一層樓”的 .NET Framework 的本機配置。接下來簡要的講解一下它的內容,以及它與 Web.config 的關係。

經過“松下問童子”,我們好不容易找到這位隱者,開啟一看,乖乖,足有 3700 多行!!“叫我怎麼能不難過,偶只想看看是啥結構,可內容實在是太多太繁瑣……”還記得偶經常對同事說的一句話麼:“辦法是人想出來的!”它不是有三千七百多行嗎,那我們就不管三七能否得出二十一啦,把它拷出來先。它不是 XML 出身嗎,那咱們就還其正身,重新命名為“machine.xml”。接著用 IE 瀏覽器將這位改頭換面的隱者開啟,把節點與注釋一一合攏。這回你看到了吧,是不是很有成就感?你要是想謝謝我,就讓我看到你在此文下面的評論吧。多多益善,呵呵。

Machine.config 與 Web.config 是啥關係?四個字 —— 父子關係。記得我在第二部分第五節講解 Web.config 作用範圍的時提到兩點 —— 繼承與覆蓋(詳見http://blog.csdn.net/cityhunter172/archive/2005/11/13/528463.aspx),在此也同樣適用。

1、  Machine.config 中的設定將作用於運行在原生所有網站及其虛擬目錄,遇到子目錄將一直繼承下去。

2、  Web.config 中的設定將覆蓋由 Machine.config 中繼承下來的對應的節點設定

說到這,再告訴大家一個秘密 —— “世上本無秘密,知道的人多了,便成了不是秘密的秘密!”

a、  Machine.config 中的 <system.web> 節點所有內容都能出現在項目根目錄下的 Web.config 中,也就是說能在 Web.config 中的內容已經在 Machine.config 中一一列出;

b、  其中 <system.web> 節點下的 <pages> 還能出現在頁面上,如: HTML 視圖下,在WebForm1.aspx 的第一行加上<pages> 的節點內容validateRequest="false" (此句意思是不對WebForm1.aspx頁面文字框輸入的值,是否包含 “<” “>” 等等具有危險性的代碼進行檢查,下一節將具體運用到)

<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false" Inherits="FromTest.WebForm1" validateRequest="false"  %>

十、  單點登入(Single Sign On)的前提條件

之前說了這麼多關於 Machine.config 的事,都是為了實現單點登入作鋪墊,那何為單點登入(Single Sign On)?從字面理解就是在一個地方登入,通常運用於 ASP.NET 分布式環境中(跨單個伺服器上的多個應用程式或在網路場中)的 Forms 身分識別驗證。打個比方,就好比現在 Sohu(搜狐) 與 Chinren(中國校友錄) 的做法,我在 Sohu 登入以後就不需要在 Chinaren 登入了。台灣與香港又把 Single Sign On 稱之為“單一登入”。

要想實現此功能,首要條件是需要一組用於加密與驗證加密的密鑰。它們位於 Machine.config 中,修改  <system.web> 節點下的 <machineKey> 節點屬性,如下:

     <machineKey firstKey="172" copyrightKey="Cityhunter172" validationKey="AD117F2F286CDCB15A9D1D4535E16DB0248026939**AUTHOR**CITYHUNTER172****WEBSITE**172*MEIBU*COM****MAILTO**CITYHUNTER172@126*COM*****F2F286CDCB15A9D1D4535E16DB0248026939" secondKey="meibu" decryptionKey="3C89AE62AD117F2F286CDCB15A9D1D4535E16DB0248026939" validation="SHA1" thirdKey="com" />

1、  validationKey 為用於驗證加密資料的密鑰。最小長度為 40 個字元(20 位元組),最大長度為 128 個字元(64 位元組)。

2、  decryptionKey 為用於加密資料的密鑰。長度只有 16 個字元(8 位元組)與 48 個字元(24 位元組)兩種。

3、  validation 為用資料驗證使用的加密類型。擁有“SHA1”“MD5”“3DES”三種方法

4、  大夥參照上述 <machineKey> 試著在WebForm1.aspx運行下列語句:

this.TextBox2.Text ="ht"+"tp"+"://"+firstKey+"."+secondKey +"."+thirdKey

大家在修改之前請先備份一下 Machine.config ,到時要是出錯可別怪我沒提醒你。以上密鑰並不是胡亂得來的,接下來向大家介紹產生密鑰的方法。

我們把上一節中提到的 WebForm1.aspx 拖入本項目的 Public 目錄下,再往頁面上拖入一個 TextMode=MultiLine 的TextBox3 與一個 Button 編寫按鈕事件與函數:

   private void Button1_Click(object sender, System.EventArgs e)

   {

        string decStr = this.CreateKeyString(int.Parse(this.TextBox1.Text));

        string valStr = this.CreateKeyString(int.Parse(this.TextBox2.Text));

        this.TextBox3.Text=string.Format("<machineKey validationKey=\"{0}\" decryptionKey=\"{1}\" validation=\"SHA1\"/>",valStr,decStr);

     }

   /// <summary>

   /// 產生加密型強隨機 Key 值

   /// </summary>

   /// <param name="i">Key 的有效長度:

   /// decryptionKey 的有效值為 8 或 24;

   /// validationKay 的有效值為 20 至 64

   /// </param>

   private string CreateKeyString(int i)

   {

        System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();  //加密隨機數產生器

        byte[] bt = new byte[i];

        rng.GetBytes(bt);//用加密型強隨機值序列填充位元組數組

        System.Text.StringBuilder str = new System.Text.StringBuilder();

        for(int j= 0;j<i;j++)

        {

             str.Append(string.Format("{0:X2}",bt[j])); //轉換成大寫的十六進位文本

        }

        return str.ToString();

   }

每次點擊按鈕產生密鑰都不同,大家不妨多點幾次。切換至 HTML 視圖,到WebForm1.aspx 第一行把 validateRequest="false" 去掉,然後再多點幾次 Button1試試,看看會有什麼效果,嘿嘿………

十一、  單點登入(Single Sign On)的網站樣本

將上述 TextBox3 產生的文本,覆蓋Machine.config 中的,現在你的機器已經具備了單點登入的條件。大夥可以再建立一個項目 FormTest2 ,從 FormTest2 登入後直接輸入 FormTest 中的Default.aspx 的網址(http://localhost/FormTest/ Default.aspx),反之亦可。

下面結合執行個體講解:偶在山東每步科技網站申請了一個免費次層網域 172.meibu.com,並下載了每步的 4.0 版的動態網域名稱解析用戶端。現在使用 ADSL 拔號上網,也就是說我的電腦已經成了 Web 服務器,同時支援 SQL Server 、Oracle 空間高達 200 G 想怎麼弄就怎麼弄,夠牛吧,嘿嘿。布署上來的項目有環勝數位網站、許可權管理系統、IT 內部管理網,以上三個項目是偶一人全權開發的。所謂全權就是從資料庫預存程序寫到 .cs 代碼再到 javascript ,最後到美工都是偶一手搞定的。^_^ 我把這三個不相干的項目做成了單點登入的模式,加上整合網站的首頁面,共有四個地方可以進行登入。因為使用者 Table 的結構不同,因此只有一個入口能在進入後,在跳轉網站時不會出錯,那就是在整合頁面登入。

現在我想把環勝數位這個網站單獨脫離出來,而剩下的兩個網站繼續實現單點登入,該怎麼做呢?或者是我的 ASP.NET 的空間是租的,服務商肯定不可能讓我修改 Machine.config ,我又咋辦哩?“辦法是人想出來滴!!”,根據上述 Machine.config 與 Web.config 的關係,我們可以把 <machineKey> 節點放入項目根目錄下Web.config的 <system.web> 節點。如下:

1、  許可權管理系統項目的 Web.config 用於 Form 認證的設定

<machineKey validationKey="AD117F2F286CDCB15A9D1D4535E16DB0248026939**AUTHOR**CITYHUNTER172****WEBSITE**172*MEIBU*COM****MAILTO**CITYHUNTER172@126*COM*****F2F286CDCB15A9D1D4535E16DB0248026939" decryptionKey="3C89AE62AD117F2F286CDCB15A9D1D4535E16DB0248026939" validation="SHA1" />

<authentication mode="Forms">

<forms loginUrl="Login.aspx" name="172.MEIBU.COM_WARRANT"></forms>

</authentication>

<authorization><deny users="?"></deny></authorization>

2、  IT 內部管理網項目的 Web.config 用於 Form 認證的設定

<machineKey validationKey="AD117F2F286CDCB15A9D1D4535E16DB0248026939**AUTHOR**CITYHUNTER172****WEBSITE**172*MEIBU*COM****MAILTO**CITYHUNTER172@126*COM*****F2F286CDCB15A9D1D4535E16DB0248026939" decryptionKey="3C89AE62AD117F2F286CDCB15A9D1D4535E16DB0248026939" validation="SHA1" />

<authentication mode="Forms">

<forms loginUrl="Login.aspx" name="172.MEIBU.COM_IT"></forms>

</authentication>

<authorization><deny users="?"></deny></authorization>

       大家可能會迫不急待的去試一把,偶贊成這樣的做法,因為事實是檢驗真理的唯一辦法。你不去試著自己動手,光看我在這說是很難提高的。先別急,我已經知道你想說什麼,聽聽我慢慢向你解釋:

a)       兩個項目Web.cinfig的<machineKey> 節點確保以下幾個欄位完全一樣:validationKey 、decryptionKey 、validation

b)  兩個項目的 Cookie 名稱必須相同,也就是 <forms> 中的 name 屬性,這裡我們把它統一為 name ="172.MEIBU.COM_PROJECT"

c)  注意區分大小寫

在整合的過程中,我把遇到的問題向大夥說一下,以免你們走同樣的路。

1)  首先應該是使用者管理的問題,把兩個項目的使用者整合在一起,可不是一件容易的事,原則是建立一個新的 Table 只存放帳號與密碼,用帳號做關聯,編寫觸發器,做到 Table 之間的同步;

2)  不要指望兩個項目間用 Session 進行傳值,兩個應用程式的 Session 是無法共用的。網上有人曾把類庫(編譯後的 .dll 文檔)放入同一個 bin 檔案夾實現過 Session 共用,這樣的做法實際上是把兩個項目變相合并成一個應用程式,不是我們所想要的,理由很簡單:Sohu 與 Chinaren 的伺服器分處兩地該怎麼辦?

3)  項目間的傳值,可用 Cookie 實現。在第一部分的第三節(http://blog.csdn.net/cityhunter172/archive/2005/11/06/524043.aspx)我們介紹了只要運行 System.Web.Security.FormsAuthentication.SetAuthCookie 方法即可實現登入,單點登入的實質就是含有身分識別驗證票的 Cookie 能在項目間共用。

接下來,有必要向大家介紹一下 Cookie 在 .Net 中的用法。

十二、  Cookie 在 ASP.NET 中的用法

大家也許和我一樣,很少在 ASP.NET 中使用 Cookie ,傳參數呀,存變數呀,用的比較多的是 Session 或 ViewState 以及隱藏控制項,有的乾脆用“ ? ”的請求方式。

1、  Cookie 存放的目錄

Cookie 是存放在用戶端的東東,放在“Temporary Internet Files”目錄,所以說存在安全性的問題。大夥可通過以下方式找到具體位置:開啟控制台 → Internet 選項 → 常規 → Internet 臨時檔案 → 設定 → 即可看到“當前位置”,→ 點擊“查看檔案”將直接開啟該檔案夾,你也可以點擊“移動檔案夾”變更它所在的位置。參照下圖:

      2、  Cookie 的有效期間

從上圖我們可以清楚的看到每個 Cookie 文檔的“截止期”(即為有效期間)。在有效期間內,當登入電腦的使用者 Administrator 再次訪問 172.meibu.com 時,那麼 IE 就會在請求頁面的同時,連同上述的名稱為“Cookie:administrator@172.meibu.com”的Cookie 文檔內容一起發送給伺服器。

若該文檔包含多個 Cookie 的值時,截止期則以最後的失效期為準。

3、  Cookie 的類型

這裡我們按有效期間來分,分為兩種:

a)   即時型

指的是關閉瀏覽器(所有瀏覽 172.meibu.com 的 IE)後,Cookie 便失效,此類 Cookie 不會在“Temporary Internet Files”目錄出現。其實它也有截止期的,為“0001-01-01”

b)  持久型

就是已指定具體“截止期”的,能夠在“Temporary Internet Files”目錄裡面找到的 Cookie

4、  Cookie 的內容

雙擊開啟“Cookie:administrator@172.meibu.com”,我們看到以下內容,如下圖:


       上圖中,“■”是分行符號,你若是要打破什麼鍋來問我到底是怎麼知道的話。我倒是會很樂意的告訴你:這就是經驗!偶從學習 C# 那刻起,就拿第一個 Windows 程式 —— 記事本 來開刀,儲存文檔時得來的經驗。

       所以伺服器讀出來的格式如下圖:


5、  在 ASP.NET 頁面發放 Cookie

發送上述 Cookie 的 .cs 代碼為:

        System.Web.HttpCookie ck = new HttpCookie("ckValue0");

        ck["Author"] ="CityHunter";

        ck.Expires = System.DateTime.Now.AddMinutes(10);//若不指定,則為即時型 Cookie

//ck.Path="/FormTest/ManageSys"; //設定 Cookie 的虛擬路徑,注意一定要以“/”開頭,否則為無效 Cookie ;請大家自行看一下它與在客房端的 Cookie 文檔“名稱”與 “網際網路位址”的關係

        Response.Cookies.Add(ck);


 


        ck = new HttpCookie("ckValue1"); //重新建立一個名為 ckValue1 的 Cookie

        ck.Expires = System.DateTime.Now.AddMinutes(20);   //即刻起 20 分鐘後失效

        ck["E_Mail"] ="cityhunter172@126.com";   //設定 ckValue1 中的 E_Mail 值

        ck["PersonalWeb"] ="172.meibu.com";

     Response.Cookies.Add(ck);   //添加此 Cookie

6、  取回已發放 Cookie 的值

       Response.Write(Request.Cookies["ckValue0"]["Author"]+"<br>");//用不著說明了吧

       Response.Write(Request.Cookies["ckValue1"]["E_Mail"]+"<br>");

       Response.Write(Request.Cookies["ckValue1"]["PersonalWeb"]);

       好久沒有出作業啦(何出此言?),這第三篇呀,可是花了偶兩個星期的業餘時間調試、總結、撰寫哪,都說時光貴如金,不知我花的這些時間能換來多少銀子?換銀子,我看是沒指望啦,能得到閣下的一句評論,偶也滿足了。記住,你的評論就是偶繼續寫下去的動力。

       作業:給 Cookie 賦於以下值,怎樣得到它的正確值

        ck["str1"] ="2222";

        ck["str"] ="str0=11111&str1=223";

可以肯定的是Request.Cookies["ckValue1"]["str"] 得不到 “str0=11111&str1=223”這個字串,大家不妨試一下 Request.Cookies["ckValue1"]["str1"] 會得到意想不到的字串喲。

提示:使用 Server.UrlEncode()與Server.UrlDecode()

十三、  發放永久性的驗證 Cookie

終於……終於……最後一個章節,驀然回首,洋洋洒洒十二章。沒想到年少時寫不完作文的偶,居然也能編出幾千餘字的文章來呀,不得不佩服偶自己呀!再回首,一大片暈倒的人……。永遠到底有多遠?永久究竟是多久?只有天知道。

大家登入 CSDN的時候是否留意到一個“2 周內不用再登入”的複選框,它又是怎麼做到的呢?大家是否曾遇到過這樣的困惑:在執行System.Web.Security.FormsAuthentication.SetAuthCookie 時明明已指定createPersistentCookie 為 true 為何關閉瀏覽器仍不能直接存取網站?下面我們就這個問題給大家解釋一下,且介紹如何手工建立身分識別驗證票並加入 Cookie 中。

     System.Web.Security.FormsAuthenticationTicket tk = new System.Web.Security.FormsAuthenticationTicket(

   1,           //指定版本號碼:可隨意指定

"Admin", //登入使用者名稱:對應 Web.config 中 <allow users="Admin" … /> 的 users 屬性

   System.DateTime.Now,   //發布時間

   System.DateTime.Now.AddYears(100),   //失效時間:100 年以後,夠永夠久了吧

false,   //是否為持久 Cookie:尚未發現有何用,至少目前偶還不知,下面會有說明

"測試使用者資料"//使用者資料:可用 ((System.Web.Security.FormsIdentity)User.Identity).Ticket.UserData 擷取

   );

string str = System.Web.Security.FormsAuthentication.Encrypt(tk);//加密身份驗票

      

     //聲明一個 Cookie,名稱為 Web.config 中 <forms name=".APSX" … /> 的 name 屬性,對應的值為身份驗票加密後的字串

     System.Web.HttpCookie ck = new HttpCookie(System.Web.Security.FormsAuthentication.FormsCookieName,str);   

        

     //指定 Cookie 為 Web.config 中 <forms path="/" … /> path 屬性,不指定則預設為“/”

     ck.Path=System.Web.Security.FormsAuthentication.FormsCookiePath; 


 


//此句非常重要,少了的話,就算此 Cookie 在身份驗票中指定為持久性 Cookie ,也只是即時型的 Cookie 關閉瀏覽器後就失效;因此上面我說:我是真的還不知在身份驗票中指定為持久性 Cookie 有何用。

     ck.Expires = System.DateTime.Now.AddYears(100);

Response.Cookies.Add(ck); //添加至客房端


後記

此系列文章共三部分,曆時一個月完成(2005-11-05 ~ 2005-12-06)。以上是我學習並用於實踐的一些經驗,在此拿出來與大家一起分享。代碼都是經過調試的,如有任何疑問,可在 CSDN 論壇(http://community.csdn.net/)找到我,我的 ID 是 cityhunter172 (可用此 ID 發短訊息給我),暱稱為 寒羽楓,歡迎大家批評指正。

另,發現有個別網站在轉載我的文章時,不僅刪了其中一些內容,最不能容忍的是沒有標明作者,更沒有找到出處。在此,再次希望大家在轉載時,請務必註明作者為“寒羽楓(cityhunter172)”,謝謝。



相關文章

Beyond APAC's No.1 Cloud

19.6% IaaS Market Share in Asia Pacific - Gartner IT Service report, 2018

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。