Asp.Net 用戶驗證(自定義IPrincipal和IIdentity) form 驗證

Asp.Net 用戶驗證(自定義IPrincipal和IIdentity)

作者:張子陽 日期:2009-4-14 8:39:11 出處:淘特網
[1]
<script src="http://www.tot.name/js/content_left.js" type="text/javascript"></script>
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script> <script src="http://pagead2.googlesyndication.com/pagead/expansion_embed.js"></script> <script src="http://googleads.g.doubleclick.net/pagead/test_domain.js"></script> <script>window.google_render_ad();</script>

源碼下載:http://www.tracefact.net/SourceCode/FormsAuthentication.rar

Asp.Net 用戶驗證(自定義IPrincipal和IIdentity)

引言

前一段時間有兩個朋友問我,爲什麼在HttpModule中無法獲得到Session值,因爲他們希望自定義一個HttpModule,然後在其中 獲取Session來進行用戶驗證。我奇怪爲什麼不使用.Net Framework已經提供的驗證機制,而要和Asp時一樣,自己手工進行cookie+Session驗證?我們是基於.Net Framework這個平臺進行編程,所以我覺得,在很多情況下,使用Framework已經建立好的機制會顯著地提高工作效率,而且.NET Framework內置的驗證機制通常也更加安全。

.Net提供了一整套的驗證和授權機制,這裏驗證和授權是不同的概念,驗證(Authentication)是指“證明你確實是你所說的人”,通常 是提供一個用戶名和口令,然後與持久存儲(比如數據庫)中的用戶名和口令進行對比。授權(Authorization)是指“你是否有足夠的權限做某件事 ”,此時你的身份已經被證明過了(匿名用戶、會員還是管理員),授權通常與用戶組或者用戶級別聯繫起來,不同的用戶組擁有不同的權限(訪問特定頁面或者執 行特定操作)。

回想一下我剛接觸.Net時,也曾經完全繞過.NET的驗證,自己編碼採用Cookie+Session實現身份驗證,並且一個Asp.Net 登錄控件都沒有使用,那時候的理由是:我要使用自定義的用戶表,不能使用Asp.Net安全機制在App_Data下自動生成的AspNetDB.mdf中的一系列數據表。除此以外,還有一個原因,就是.Net 驗證機制的核心IPrincipal和Identity提供的信息用戶信息太少了,當在頁面後置代碼中使用繼承來的User屬性(IPrincipal類 型)時,它的Identity屬性只有一個Name與用戶數據相關(AuthenticationType與IsAuthenticated都是與驗證相 關),而很多時候我們都需要許多額外的用戶數據。其實這只是一個誤解罷了,以爲使用Asp.Net的驗證機制和登錄控件就一定要使用其附帶的數據表,以爲Identity就只能攜帶一個Name屬性。

實際上,.NET的安全機制包括了幾個部分,除了驗證以外,還包括MemberShip、Profile、Role等,我們完全可以只使用它的驗證 機制,而繞過它的MemberShip、Profile和Role,來實現通常我們用Cookie+Session完成的功能,而且更高效更安全。這篇文 章將快速地實現這樣的一個流程。

開始前的準備

創建頁面,配置Web.config

我們先創建解決方案、建立站點,然後在站點中添加下述文件,它們將會在後面使用:

接着對Web.config進行一下配置,首先看根目錄下的Web.config:

<?xml version="1.0"?>
<configuration>
    <system.web>
        <authentication mode="Forms">
            <forms timeout="600" slidingExpiration="true" loginUrl="~/SignIn.aspx" />
        </authentication>
    </system.web>
   
    <location path="AuthOnly.aspx" >
        <system.web>
            <authorization>
                <deny users="?" />
            </authorization>
        </system.web>
    </location>
</configuration>

這裏我們指定了採用Forms驗證,並且設置用戶身份驗證過期時間爲600分鐘(默認爲30分鐘),slidingExpiration的意思是說 timeout採用絕對時間還是滑動時間,當採用滑動時間時,如果在timeout時間內再次瀏覽頁面,用戶的最後活躍時間將設爲當前時間,並重新開始計 算,這裏我們採用滑動時間。loginUrl指定了登錄頁面,當匿名用戶訪問需要驗證後才能訪問的頁面時,將會到自動導航到這裏所設置的 SignIn.aspx頁面,默認爲Login.aspx。

接着我們指定AuthOnly.aspx頁面爲只有驗證過的用戶纔可以訪問。然後創建了AuthOnly文件夾,在其下添加了一個web.config,對這個目錄進行設置,指定該文件夾下所有文件只允許驗證用戶進行訪問。

<configuration>
    <system.web>
         <authorization>
             <deny users="?" />
         </authorization>
    </system.web>
</configuration>

創建用戶數據表和數據訪問

既然是用戶登錄,所以我們自然需要一張用戶表,在App_Data下創建一個SiteData數據庫,然後添加一張User用戶表,表的設置如下:

這個表模擬了一個小型的論壇用戶表,字段的含義基本都是自解釋的,UserImage是用戶頭像的地址,PostCount是用戶的發帖 數,ReplyCount是用戶的回帖數,Level是用戶的級別。我已經爲表中添加了兩條範例數據,其中一條用戶名爲JimmyZhang,密碼爲 password。

接下來我們需要添加一個存儲過程,這個存儲過程接收一個name參數,和一個password輸出參數,根據name判斷User表中是否存在該用戶,如果存在,則由password帶回正確的密碼:

ALTER PROCEDURE dbo.IsValidUser
(
    @userName varchar(50),
    @password varchar(50) OUTPUT
)
AS
    if Exists(Select Id From [User] Where [Name] = @userName)
        Begin
            Select @password = Password From [User] Where [name]= @userName
            Select 1        -- Ture
        End    
Select 0        -- false

這樣做的目的是爲了程序能夠區分“不存在此用戶”和“用戶存在,但是密碼不正確”這兩種情況。如果Select的where子句爲 [name]=@userName and [password] = @password,則無法進行區分。由數據庫帶回了正確的密碼之後,我們只需要在程序中與用戶輸入的密碼進行對比就可以知道用戶的密碼是否正確。

接下來我們創建一個強類型DataSet作爲我們的數據訪問層,因爲我發現使用強類型DataSet作數據訪問是最快的,基本不需要編寫一行代碼, 在App_Code中添加一個AuthDataSet數據集文件,然後將User表拖進去,另外配置一下UserTableAdapter,添加兩個方 法,一個是GetUserTable(@name),它根據name參數獲得用戶信息;一個是IsValidUser(@userName, @password),它調用了上面的存儲過程,並且返回一個標量值(0或者1)。

配置好以後,你的AuthDataSet應該和下面一樣:

如果你查看一下生成的IsValidUser()方法,就會發現它具有這樣的簽名:

public virtual object IsValidUser(string userName, ref string password)

由於它返回的是一個object類型,並且接收的是一個ref參數,儘管這樣最通用,但是可能不夠方便,注意到UserTableAdapter是一個部分類,所以我們可以在App_Code中再創建一個UserTableAdapter部分類,對它進行一個簡單的包裝:

namespace AuthDataSetTableAdapters {

    // 檢查是否是正確的用戶名,如果是正確的用戶名,帶回正確的密碼
    public partial class UserTableAdapter {    
        public bool IsValidUserST(string userName, out string password) {
            password = "";
            return Convert.ToBoolean(this.IsValidUser(userName, ref password));        
        }
    }
}

這裏的方法後綴ST,意思是StrongType(強類型)。好了,現在我們的數據訪問就已經OK了,接下來我們看一下第一個頁面:SignIn.aspx用戶登錄頁面。

用戶登錄 -- 爲Identity添加用戶數據

Login.aspx頁面實現

在登錄頁面,我們需要針對登錄用戶和非登錄用戶做不同的處理:如果用戶尚未登錄,則顯示登錄用的表單;如果用於已經登錄了,則顯示登錄用戶名並進行提示。完成這件事最好就是使用LoginView控件和LoginName控件了:

<asp:LoginView ID="LoginView1" runat="server">
    <LoggedInTemplate>
        <asp:LoginName ID="LoginName1" runat="server" />
        ,你已經登錄了^_^ <br /><br />
                 
        你可以選擇 <asp:LoginStatus ID="LoginStatus1" runat="server" LogoutPageUrl="~/Logout.aspx" LogoutAction="Redirect"  />
    </LoggedInTemplate>
    <AnonymousTemplate>
        用戶名:<asp:TextBox ID="txtUserName" runat="server" Width="128px"></asp:TextBox>
        <br />
        密 碼:<asp:TextBox ID="txtPassword" runat="server"></asp:TextBox>
        <br />
        <asp:Button ID="btnLogin" runat="server" Text="登 錄" οnclick="btnLogin_Click" Width="100px" />
        <br />
        <br />
        <asp:Label ID="lbMessage" runat="server" ForeColor="Red" Text=""></asp:Label>
    </AnonymousTemplate>
</asp:LoginView>

這裏的關鍵是“登錄”按鈕的代碼後置文件,在“引言”部分,我們提到了Identity中的信息太少,爲了向Identity中添加信息,我們可以 先獲得FormsIdentity的Ticket屬性,它是一個FormsAuthenticationTicket類型,它含有一個UserData字 符串屬性可以用於承載我們的用戶數據,遺憾的是這個屬性是隻讀的,爲了給這個屬性賦值,我們需要重新新構建一個 FormsAuthenticationTicket,並在構造函數中傳入我們想要添加的用戶信息。 FormasAuthenticationTicket包含了諸多用於用戶驗證的信息,它從Cookie中獲得,可以認爲它是服務端對Cookie的一個 包裝,只是這裏的Cookie的操作不需要我們來處理,而由Asp.Net運行時去處理。具體的代碼如下:

public partial class SignIn : System.Web.UI.Page {

    private enum LoginResult {
        Success,
        UserNotExist,
        PasswordWrong
    }

    // 用戶登錄
    private LoginResult Login(string userName, string password) {

        string validPassword;   // 包含正確的密碼
        AuthDataSetTableAdapters.UserTableAdapter adapter =
            new AuthDataSetTableAdapters.UserTableAdapter();

        // 判斷用戶名是否正確
        if (adapter.IsValidUserST(userName, out validPassword)) {
            // 判斷密碼是否正確
            if (password.Equals(validPassword))
                return LoginResult.Success;
            else
                return LoginResult.PasswordWrong;
        }

        // 用戶名不存在
        return LoginResult.UserNotExist;
    }
   
    protected void btnLogin_Click(object sender, EventArgs e) {

        TextBox txtUserName = LoginView1.FindControl("txtUserName") as TextBox;
        TextBox txtPassword = LoginView1.FindControl("txtPassword") as TextBox;
        Label lbMessage = LoginView1.FindControl("lbMessage") as Label;

        string userName = txtUserName.Text;
        string password = txtPassword.Text;

        LoginResult result = Login(userName, password);

        string userData = "登錄時間" + DateTime.Now.ToString();

        if (result == LoginResult.Success) {
            SetUserDataAndRedirect(userName, userData);        
        } else if (result == LoginResult.UserNotExist) {
            lbMessage.Text = "用戶名不存在!";
        }else {
            lbMessage.Text = "密碼有誤!";
        }
    }


    // 添加自定義的值,然後導航到來到此頁面之前的位置
    private void SetUserDataAndRedirect(string userName, string userData) {
        // 獲得Cookie
        HttpCookie authCookie = FormsAuthentication.GetAuthCookie(userName, true);

        // 得到ticket憑據
        FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(authCookie.Value);

        // 根據之前的ticket憑據創建新ticket憑據,然後加入自定義信息
        FormsAuthenticationTicket newTicket = new FormsAuthenticationTicket(
            ticket.Version, ticket.Name, ticket.IssueDate,
            ticket.Expiration, ticket.IsPersistent, userData);

        // 將新的Ticke轉變爲Cookie值,然後添加到Cookies集合中
        authCookie.Value = FormsAuthentication.Encrypt(newTicket);
        HttpContext.Current.Response.Cookies.Add(authCookie);

        // 獲得 來到登錄頁之前的頁面,即url中return參數的值
        string url = FormsAuthentication.GetRedirectUrl(userName, true);

        Response.Redirect(url);
    }
}

我們首先定義了一個枚舉,用來說明點擊登錄後的狀態:Success(成功)、UserNotExsit(用戶不存在)以及 PasswordWrong(用戶名存在,但密碼錯)。Login()方法調用了上一小節我們定義的強類型DataSet中的 IsUserValidST()方法,然後返回登錄結果。“搜索”按鈕的事件處理方法反而非常簡單,如果登錄失敗時在頁面顯示失敗原因,如果登錄成功則調 用SetUserDataAndRedirect()方法。

在SetUserDataAndRedirect()方法中,我們執行了主要的邏輯,我們先獲得了Asp.Net用於驗證的Cookie,從 Cookie中得到FormsAuthenticationTicket,最後,執行了前面所敘述的步驟,將我們自定義的數據 -- 當前用戶的登錄時間記錄到了一個新構建的FormsAuthenticationTicket中,最後將它進行編碼然後賦值給Cookie。接着我們導航 到了來到SignIn.aspx之前所在的頁面。

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參數總是有效的,因此當搜索數據庫找不到記錄時,我簡單地拋出了異常。

Default.aspx 頁面預覽

我們再次修改Default.aspx,添加用於顯示用戶詳細信息的控件和HTML標記:

<asp:Panel ID="pnlUserInfo" runat="server" Visible="false">
    <table class="mainTable" style="width:280px">
        <tr>
            <th style="background:#f5f5f5;text-align:center" colspan="2">用戶信息</th>
        </tr>
        <tr>
            <td colspan="2" style="text-align: center">
                <asp:Image ID="imgHeadImage" runat="server" />
            </td>
        </tr>
        <tr>
            <td style="width:28%;">姓名:</td>
            <td>
                <asp:Literal ID="ltrName" runat="server"></asp:Literal>
            </td>
        </tr>
        <tr>
            <td>註冊日期:</td>
            <td>
                <asp:Literal ID="ltrRegisterDate" runat="server"></asp:Literal>
            </td>
        </tr>
        <tr>
            <td>電子郵件:</td>
            <td>
                <asp:Literal ID="ltrEmail" runat="server"></asp:Literal>
            </td>
        </tr>
        <tr>
            <td>個人主頁:</td>
            <td>
                <asp:HyperLink ID="lnkHomepage" runat="server"></asp:HyperLink>
            </td>
        </tr>
        <tr>
            <td>發帖數:</td>
            <td>
                <asp:Literal ID="ltrPostCount" runat="server"></asp:Literal>
            </td>
        </tr>
        <tr>
            <td>回帖數:</td>
            <td>
                <asp:Literal ID="ltrReplyCount" runat="server"></asp:Literal>
            </td>
        </tr>
        <tr>
            <td>用戶等別:</td>
            <td>
                <asp:Image ID="imgUserLevel" runat="server" />
            </td>
        </tr>
    </table>
</asp:Panel>

然後修改頁面的後置代碼:

protected void Page_Load(object sender, EventArgs e) {
    if (!IsPostBack) {
        if (Request.IsAuthenticated) {

            // 上面相同

            SiteUser user = SiteUser.GetUser(identity.Name);
            PopulateControls(user);
        }
    }
}

private void PopulateControls(SiteUser user) {
    ltrEmail.Text = user.Email;
    ltrName.Text = user.Name;
    ltrPostCount.Text = user.PostCount.ToString();
    ltrRegisterDate.Text = user.RegisterDate.ToShortDateString();
    ltrReplyCount.Text = user.ReplyCount.ToString();
    lnkHomepage.Text = user.HomePage;
    lnkHomepage.NavigateUrl = user.HomePage;

    imgHeadImage.ImageUrl = "~/Images/" + user.UserImage;
    imgUserLevel.ImageUrl =
        String.Format("~/Images/Star{0}.gif", user.Level);

    pnlUserInfo.Visible = true;
}

這裏,我們從Identity中獲得用戶的名稱,然後再調用SiteUser的GetUser()方法,獲得了一個SiteUser對象,最後使用這個SiteUser對象對頁面控件進行了賦值。下面是最後的頁面效果:

總結

在這篇文章中我們看到了如何使用Asp.Net內置機制實現用戶驗證的功能,並且通過FormsAuthenticationTicket的UserData屬性、自定義IPrincipal和IIdentity、以及自定義對象三種方式實現了附加 (獲取)用戶數據。

本文所附帶的代碼中,還有一些頁面只有登錄用戶才能進行訪問,但在這篇文章中我沒有演示和說明。使用.Net的驗證機制,我們可以通過僅在 Web.config設置一下,就擁有了以前需要編碼才能實現的限制頁面訪問的功能。通過這篇文章,我希望大家能夠看到,大多數情況下,我們都可以使 用.Net的自定義驗證系統,而沒有必要再重複造輪子去實現自己的驗證方式。

感謝閱讀,希望這篇文章能給你帶來幫助。

發佈了115 篇原創文章 · 獲贊 11 · 訪問量 84萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章