標籤:current post cti arc .com gis thread ace event
本文轉自:http://www.cnblogs.com/amylis_chen/archive/2012/08/02/2620129.html
Default.aspx 頁面預覽預設情況下SignIn.aspx在登入成功後會導航到Default.aspx頁面,所以我們先簡單的構建一下Default.aspx頁面,看看實現的效果:<asp:LoginView ID="LoginView1" runat="server"> <AnonymousTemplate> 歡迎訪問, 遊客 ! </AnonymousTemplate> <LoggedInTemplate> 你好, <asp:LoginName ID="LoginName1" runat="server" /> ! <br /> <strong>UserData值:</strong> <asp:Literal ID="lbUserData" runat="server" /> </LoggedInTemplate></asp:LoginView><br /><asp:LoginStatus ID="LoginStatus1" runat="server" LogoutPageUrl="~/Logout.aspx" LogoutAction="Redirect" />類似地,我們放置了一個LoginView控制項,只是這裡我們多放置了一個LoginStatus控制項。接下來我們看一下後置代碼:protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { if (Request.IsAuthenticated) { FormsIdentity identity = User.Identity as FormsIdentity; string userData = identity.Ticket.UserData; Literal lbUserData = LoginView1.FindControl("lbUserData") as Literal; lbUserData.Text = userData; } }}最後我們先進行登入,然後再開啟Default.aspx頁面,會看到類似這樣的輸出:至此,我們已經看到了如何利用FormsAuthentionTicket來附帶額外的使用者資料,但是我們應該看到這種做法存在的問題:可以儲存的資料過於單一,僅僅只是一個字串。而我們第一節中所介紹的使用者表包括各種類型的各種資料。如果你看過了 從一個範例看XML的應用 這篇文章,你應該立刻想到此處又是一個“單一字串儲存多種不同類型資料”的應用情境,我們可以定義XML來解決。對於這種方式,我不再示範了。實際上,我們可以自訂一個IPrincipal和IIdentity來完成,接下來就來看一下。自訂IPrincipal和IIdentity不管是在Windows上還是在Web上,.Net都使用這兩個介面來實現使用者的身分識別驗證。它們不過是一個介面,實現了這兩個介面的類型附帶了使用者的資訊,最終被賦予線程(Windows)或Cookie(Web)來對使用者進行驗證。我們在App_Code下添加CustomPrincipal和CustomIdentity來實現這兩個介面:public class CustomPrincipal : IPrincipal { private CustomIdentity identity; public CustomPrincipal(CustomIdentity identity) { this.identity = identity; } public IIdentity Identity { get { return identity; } } public bool IsInRole(string role) { return false; }}public class CustomIdentity : IIdentity { private FormsAuthenticationTicket ticket; private HttpContext context = HttpContext.Current; public CustomIdentity(FormsAuthenticationTicket ticket) { this.ticket = ticket; } public string AuthenticationType { get { return "Custom"; } } public bool IsAuthenticated { get { return true; } } public string Name { get { return ticket.Name; } } public FormsAuthenticationTicket Ticket { get { return ticket; } } // 這裡可以是任意來自資料庫的值,由Name屬性取得 // 需要注意此時已通過身分識別驗證 public string Email { get { HttpCookie cookie = context.Request.Cookies["Email"]; if (cookie==null || String.IsNullOrEmpty(cookie.Value)) { string type = "jimmy_dev[at]163.com"; // 實際應根據name屬性從資料庫中獲得 cookie = new HttpCookie("UserType", type); cookie.Expires = DateTime.Now.AddDays(1); context.Response.Cookies.Add(cookie); } return cookie.Value; } } public string HomePage { get { HttpCookie cookie = context.Request.Cookies["HomePage"]; if (cookie==null || String.IsNullOrEmpty(cookie.Value)) { string name = "www.tracefact.net"; // 實際應根據name屬性從資料庫中獲得 cookie = new HttpCookie("NickName", name); cookie.Expires = DateTime.Now.AddDays(1); context.Response.Cookies.Add(cookie); } return cookie.Value; } }}注意這裡的HomePage和Email這兩個屬性,它們攜帶了我們的使用者資料,這裡我僅僅是對它們進行了一個簡單的賦值,實際的數值應該是來自於資料庫。還要注意擷取到它們的值後被儲存在了Cookie中,以避免頻繁的對資料庫進行訪問。定義了實現這兩個介面的對象之後,我們還需要把它嵌入到應用程式的生命週期中,具體的做法就是掛接到HttpModule或者是重寫Global.asax中的事件,這裡我採用了重寫Global.asax事件的方式,因此建立一個Global.asax檔案,然後添加如下代碼:void Application_OnPostAuthenticateRequest(object sender, EventArgs e) { IPrincipal user = HttpContext.Current.User; if (user.Identity.IsAuthenticated && user.Identity.AuthenticationType == "Forms") { FormsIdentity formIdentity = user.Identity as FormsIdentity; CustomIdentity identity = new CustomIdentity(formIdentity.Ticket); CustomPrincipal principal = new CustomPrincipal(identity); HttpContext.Current.User = principal; Thread.CurrentPrincipal = principal; }}這段代碼很好理解,它不過是在應用程式的PostAuthenticateRequest事件中用我們自訂的CustomPrincipal和CustomIdentity替換掉了預設的IPrincipal和IIdentity實現。Default.aspx頁面預覽我們再次對Default.aspx進行修改,添加兩個Literal控制項,用於顯示我們自訂的數值:自訂Identity中的值:<br /><strong>Email:</strong><asp:Literal ID="ltrEmail2" runat="server"></asp:Literal><br /><strong>HomePage:</strong><asp:Literal ID="ltrHomePage" runat="server"></asp:Literal><br />然後修改頁面的代碼,使用我們的自訂CustomIdentity,然後從中獲得自訂的屬性值:protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { if (Request.IsAuthenticated) { CustomIdentity identity = User.Identity as CustomIdentity; if (identity != null) { // 獲得UserData中的值 string userData = identity.Ticket.UserData; Literal lbUserData = LoginView1.FindControl("lbUserData") as Literal; lbUserData.Text = userData; // 獲得identity中的值 ltrEmail2.Text = identity.Email; ltrHomePage.Text = identity.HomePage; } } }}如果你現在開啟頁面,將會看到類似下面的頁面:可以看到我們獲得了定義在CustomIdentity中的屬性。注意這裡我只是做了一個示範,因此只在CustomIdentity中包含了Email和HomePage兩個屬性值,如果看到此處你便以為大功告成,然後將所有未完成的屬性都添加到CustomIdentity中去就大錯特錯了。Identity的目的只是為你提供一個已經登入了的使用者的名稱,而不是攜帶所有的使用者資訊,這些資訊應該由其他的類型提供。因此微軟才定義了MemberShipUser類型和Profile。從這個角度上來看,自訂IPrincipal和IIdentity並沒有太大的意義。這裡,我們最好是定義一個自己的類型來承載使用者資料,下面我們就看下如何完成。自訂類型攜帶使用者資料在App_Code中建立一個SiteUser類,它的實現如下,簡單起見,我使用了公有欄位而非屬性:public class SiteUser{ public string Name; public string UserImage; public DateTime RegisterDate; public string Email; public string HomePage; public int PostCount; public int ReplyCount; public byte Level; public SiteUser(AuthDataSet.UserRow userRow) { this.Email = userRow.Email; this.HomePage = userRow.Homepage; this.Level = userRow.Level; this.Name = userRow.Name; this.PostCount = userRow.PostCount; this.RegisterDate = userRow.RegisterDate; this.ReplyCount = userRow.ReplyCount; this.UserImage = userRow.UserImage; } // 實際應該由資料庫獲得 public static SiteUser GetUser(string name) { AuthDataSetTableAdapters.UserTableAdapter adapter = new AuthDataSetTableAdapters.UserTableAdapter(); AuthDataSet.UserDataTable userTable = adapter.GetUserTable(name); if(userTable.Rows.Count >0){ return new SiteUser((AuthDataSet.UserRow)userTable.Rows[0]); } // 因為調用這個方法時,name應該是有效, // 如果name無效,直接拋出異常 throw new ApplicationException("User Not Found"); }}它的GetUser()靜態方法根據使用者的名稱獲得了一個SiteUser對象,這裡需要注意的是通常調用這個方法時,使用者已經登入過了,也就是說其name參數總是有效,因此當搜尋資料庫找不到記錄時,我簡單地拋出了異常。
[轉]Asp.Net 使用者驗證(自訂IPrincipal和IIdentity)