使用Forms Authentication实现用户注册、登录 (三)用户实体替换
生活随笔
收集整理的這篇文章主要介紹了
使用Forms Authentication实现用户注册、登录 (三)用户实体替换
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
使用Forms Authentication實現用戶注冊、登錄 (三)用戶實體替換 收藏
IPrincipal和IIdentity
通過查閱文檔,我們可以看到HttpContext.User屬性的類型是IPrincipal接口。然而我們知道,接口通常是不能直接訪問的,其背后必定隱藏了一個實現了該接口的對象。那么這個實際對象的類型是什么呢?
讓我們在前面示例的MasterPage的Page_Init方法上加一個斷點,再次運行程序,可以得到HttpContext.User屬性的真正類型是System.Security.Principal.GenericPrincipal。
查看IPrincipal接口的定義,可以看到它只有一個公開屬性——Identity,其類型是這里要提到的另外一個重要接口IIdentity。通過上面的斷點跟蹤,我們還能知道對于GenericPrincipal而言,其Identity屬性的實際類型是GenericIdentity,也是位于System.Security.Principal命名空間中。
由此,我們引出了.NET Framework中關于Principal(實體)的整個類型系統。所有這些類型都位于mscorlib.dll程序集中,由此也可以看出,這套模型隸屬于整個系統的基石。
?
實現自己的IPrincipal
要想用自己的實體對象替換HttpContext.User,就必須讓自己的實體對象實現IPrincipal接口;通常還必須伴隨著實現IIdentity接口。
目前系統中有的是一個數據實體對象。一般而言,實現IPrincipal接口有一下兩種方式——
l 編寫單獨的類型實現IPrincipal接口,并在其中包含數據實體對象;
l 修改數據實體對象使其實現IPrincipal接口。
對于這兩種方式而言,其Identity屬性可以通過以下三種方式實現——
l 使用.NET Framework提供的GenericIdentity;
l 創建自定義的類,實現Identity接口;
l 修改數據實體對象或自定義的實體類,讓它們同時實現IPrincipal和IIdentity接口。
對于簡單的應用程序而言,通常可以修改數據實體對象,使其同時實現IPrincipal和IIdentity接口。而就復雜的分層架構應用程序,則建議在邏輯層創建分別實現了IPrincipal和IIdentity接口的對象。本文的示例????? 明顯屬于前一種情況,因此我們考慮修改作為數據實體類的UserObject類,讓其實現兩個接口。以下是修改完畢的UserObject類:
?
?1?public?class?UserObject?:?IPrincipal,?IIdentity
?2?{
?3??????///<summary>
?4??????///用戶名。
?5??????///</summary>
?6??????public?string?Name;
?7??
?8??????///<summary>
?9??????///密碼散列值。
10??????///</summary>
11??????public?string?PasswordHash;
12??
13??????///<summary>
14??????///密碼salt值。
15??????///</summary>
16??????public?string?PasswordSalt;
17??
18??????#region?IIdentity?Members
19??
20??????public?string?AuthenticationType
21??????{
22??????????get
23??????????{
24???????????????return?"Froms";
25??????????}
26??????}
27??
28??????public?bool?IsAuthenticated
29??????{
30??????????get
31??????????{
32???????????????return?true;
33??????????}
34??????}
35??
36??????string?IIdentity.Name
37??????{
38??????????get
39??????????{
40???????????????return?this.Name;
41??????????}
42??????}
43??
44??????#endregion
45??
46??????#region?IPrincipal?Members
47??
48??????public?IIdentity?Identity
49??????{
50??????????get
51??????????{
52???????????????return?this;
53??????????}
54??????}
55??
56??????public?bool?IsInRole(string?role)
57??????{
58??????????return?false;
59??????}
60??
61??????#endregion
62?}
?
首先我們來看一下對IIdentity接口的實現。該接口要求三個屬性——AuthenticationType、IsAuthenticated和Name。AuthenticationType表示該用戶標識所使用的驗證類型,這里返回的是“Forms”;IsAuthenticated屬性表示當前用戶是否已經通過驗證(即是否已登錄。在這個例子里,我們只針對已登錄用戶進行實體替換,所以這個屬性總是返回true。通常,實際的Web應用程序編寫時還有一種習慣,就是為未登錄用戶(稱之為匿名用戶)也提供一個用戶實體對象,此時就需要為IsAuthenticated提供邏輯,判斷用戶是否已通過驗證了。最后IIdentity接口還要求對象提供一個Name屬性,在這里,由于已經存在了Name字段,因此才用“顯示接口實現”來提供Name屬性,返回對象自身的Name字段即可。
接下來我們看一下IPrincipal接口的實現。該接口要求提供一個Identity屬性和一個IsInRole方法。由于UserObject類本身已經實現了IIdentity接口,因此在Identity屬性中直接reutren this即可。因為我們這個示例不涉及用戶分組(角色)方面的技術,因此IsInRole方法總是返回false。
?
用戶實體替換
用戶實體替換即使用我們自己編寫的類型的實例來替換HttpContext.User屬性。實體替換應該發生在HttpApplication的PostAuthenticateRequest事件發生時,因為此時ASP.NET已經從客戶端得到了用戶憑證Cookie并進行了解密和校驗。
我們既可以編寫一個HttpModule來處理PostAuthenticateRequest事件,也可以在Global..asax文件中添加時間處理器。這里為了簡單,我們選擇在Global.asax中添加如下事件處理器:
?
?1?void?Application_PostAuthenticateRequest(object?sender,?EventArgs?e)
?2?{
?3??????HttpApplication?app?=?(HttpApplication)sender;
?4??????if(app.Context.User.Identity.Name?!=?"")?//?僅在已登錄時替換
?5??????{
?6??????????UserObject?user?=?DataAccess.GetUserByName(app.Context.User.Identity.Name);
?7??????????app.Context.User?=?user;
?8??????????Thread.CurrentPrincipal?=?user;
?9??????}
10?}
11??
在這里我們首先進行了判斷,如果用戶已登錄,才進行實體替換。當然你也可以選擇未未登錄用戶也提供一個匿名用戶實體。
接下來,我們通過本來已經存放在HttpContext.User.Identity中的用戶標識得到了數據實體對象,然后分別將其賦予HttpContext.User和Thread.CurrentPrincipal。
至此,我們的示例代碼就完工了。沒有提到的是,完成了這一步之后,你就可以通過類似下面的代碼在任何可以訪問到HttpContext的地方獲取用戶實體了:
?
?1?UserObject?user?=?HttpContext.Current.User?as?UserObject;
?2?if(user?!=?null)
?3?{
?4????????//?可以使用user
?5?}
?6?else
?7?{
?8????????//?用戶未登錄
?9?}
10??
需要注意,由于在這里我們僅對已登錄用戶進行了用戶實體替換,所以代碼使用as進行類型轉換并結合if語句進行判斷是必需的。
?
小結
好吧,這一部分說的是用戶實體替換。
?
2007年過去了,我很懷念。
IPrincipal和IIdentity
通過查閱文檔,我們可以看到HttpContext.User屬性的類型是IPrincipal接口。然而我們知道,接口通常是不能直接訪問的,其背后必定隱藏了一個實現了該接口的對象。那么這個實際對象的類型是什么呢?
讓我們在前面示例的MasterPage的Page_Init方法上加一個斷點,再次運行程序,可以得到HttpContext.User屬性的真正類型是System.Security.Principal.GenericPrincipal。
查看IPrincipal接口的定義,可以看到它只有一個公開屬性——Identity,其類型是這里要提到的另外一個重要接口IIdentity。通過上面的斷點跟蹤,我們還能知道對于GenericPrincipal而言,其Identity屬性的實際類型是GenericIdentity,也是位于System.Security.Principal命名空間中。
由此,我們引出了.NET Framework中關于Principal(實體)的整個類型系統。所有這些類型都位于mscorlib.dll程序集中,由此也可以看出,這套模型隸屬于整個系統的基石。
?
實現自己的IPrincipal
要想用自己的實體對象替換HttpContext.User,就必須讓自己的實體對象實現IPrincipal接口;通常還必須伴隨著實現IIdentity接口。
目前系統中有的是一個數據實體對象。一般而言,實現IPrincipal接口有一下兩種方式——
l 編寫單獨的類型實現IPrincipal接口,并在其中包含數據實體對象;
l 修改數據實體對象使其實現IPrincipal接口。
對于這兩種方式而言,其Identity屬性可以通過以下三種方式實現——
l 使用.NET Framework提供的GenericIdentity;
l 創建自定義的類,實現Identity接口;
l 修改數據實體對象或自定義的實體類,讓它們同時實現IPrincipal和IIdentity接口。
對于簡單的應用程序而言,通常可以修改數據實體對象,使其同時實現IPrincipal和IIdentity接口。而就復雜的分層架構應用程序,則建議在邏輯層創建分別實現了IPrincipal和IIdentity接口的對象。本文的示例????? 明顯屬于前一種情況,因此我們考慮修改作為數據實體類的UserObject類,讓其實現兩個接口。以下是修改完畢的UserObject類:
?
?1?public?class?UserObject?:?IPrincipal,?IIdentity
?2?{
?3??????///<summary>
?4??????///用戶名。
?5??????///</summary>
?6??????public?string?Name;
?7??
?8??????///<summary>
?9??????///密碼散列值。
10??????///</summary>
11??????public?string?PasswordHash;
12??
13??????///<summary>
14??????///密碼salt值。
15??????///</summary>
16??????public?string?PasswordSalt;
17??
18??????#region?IIdentity?Members
19??
20??????public?string?AuthenticationType
21??????{
22??????????get
23??????????{
24???????????????return?"Froms";
25??????????}
26??????}
27??
28??????public?bool?IsAuthenticated
29??????{
30??????????get
31??????????{
32???????????????return?true;
33??????????}
34??????}
35??
36??????string?IIdentity.Name
37??????{
38??????????get
39??????????{
40???????????????return?this.Name;
41??????????}
42??????}
43??
44??????#endregion
45??
46??????#region?IPrincipal?Members
47??
48??????public?IIdentity?Identity
49??????{
50??????????get
51??????????{
52???????????????return?this;
53??????????}
54??????}
55??
56??????public?bool?IsInRole(string?role)
57??????{
58??????????return?false;
59??????}
60??
61??????#endregion
62?}
?
首先我們來看一下對IIdentity接口的實現。該接口要求三個屬性——AuthenticationType、IsAuthenticated和Name。AuthenticationType表示該用戶標識所使用的驗證類型,這里返回的是“Forms”;IsAuthenticated屬性表示當前用戶是否已經通過驗證(即是否已登錄。在這個例子里,我們只針對已登錄用戶進行實體替換,所以這個屬性總是返回true。通常,實際的Web應用程序編寫時還有一種習慣,就是為未登錄用戶(稱之為匿名用戶)也提供一個用戶實體對象,此時就需要為IsAuthenticated提供邏輯,判斷用戶是否已通過驗證了。最后IIdentity接口還要求對象提供一個Name屬性,在這里,由于已經存在了Name字段,因此才用“顯示接口實現”來提供Name屬性,返回對象自身的Name字段即可。
接下來我們看一下IPrincipal接口的實現。該接口要求提供一個Identity屬性和一個IsInRole方法。由于UserObject類本身已經實現了IIdentity接口,因此在Identity屬性中直接reutren this即可。因為我們這個示例不涉及用戶分組(角色)方面的技術,因此IsInRole方法總是返回false。
?
用戶實體替換
用戶實體替換即使用我們自己編寫的類型的實例來替換HttpContext.User屬性。實體替換應該發生在HttpApplication的PostAuthenticateRequest事件發生時,因為此時ASP.NET已經從客戶端得到了用戶憑證Cookie并進行了解密和校驗。
我們既可以編寫一個HttpModule來處理PostAuthenticateRequest事件,也可以在Global..asax文件中添加時間處理器。這里為了簡單,我們選擇在Global.asax中添加如下事件處理器:
?
?1?void?Application_PostAuthenticateRequest(object?sender,?EventArgs?e)
?2?{
?3??????HttpApplication?app?=?(HttpApplication)sender;
?4??????if(app.Context.User.Identity.Name?!=?"")?//?僅在已登錄時替換
?5??????{
?6??????????UserObject?user?=?DataAccess.GetUserByName(app.Context.User.Identity.Name);
?7??????????app.Context.User?=?user;
?8??????????Thread.CurrentPrincipal?=?user;
?9??????}
10?}
11??
在這里我們首先進行了判斷,如果用戶已登錄,才進行實體替換。當然你也可以選擇未未登錄用戶也提供一個匿名用戶實體。
接下來,我們通過本來已經存放在HttpContext.User.Identity中的用戶標識得到了數據實體對象,然后分別將其賦予HttpContext.User和Thread.CurrentPrincipal。
至此,我們的示例代碼就完工了。沒有提到的是,完成了這一步之后,你就可以通過類似下面的代碼在任何可以訪問到HttpContext的地方獲取用戶實體了:
?
?1?UserObject?user?=?HttpContext.Current.User?as?UserObject;
?2?if(user?!=?null)
?3?{
?4????????//?可以使用user
?5?}
?6?else
?7?{
?8????????//?用戶未登錄
?9?}
10??
需要注意,由于在這里我們僅對已登錄用戶進行了用戶實體替換,所以代碼使用as進行類型轉換并結合if語句進行判斷是必需的。
?
小結
好吧,這一部分說的是用戶實體替換。
?
2007年過去了,我很懷念。
轉載于:https://www.cnblogs.com/qiantuwuliang/archive/2009/03/06/1404801.html
總結
以上是生活随笔為你收集整理的使用Forms Authentication实现用户注册、登录 (三)用户实体替换的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NFS服务器架设篇
- 下一篇: 如何创建生成非 MFC 项目的自定义 A