淺析《ASP.Net Web 站點高級編程》的登錄驗證

轉自:Zol_麥蒂

 

ASP.NET 中內置的用戶驗證支持的功能非常強大,它能夠自動地在Context對象中生成一個名爲User的屬性.
該屬性能夠讓我們訪問各種信息,包括用戶是否已經驗證。驗證用戶的類型,甚至還有用戶名,不管我們是
使用基於表單的驗證還是WINDOWS驗證,都可以使用由Context對象表示的當前的HttpContext實例中的User對象

.Net FrameWork中提供的Context.User對象與前面介紹的User類不同。Context.User用於驗證,
而User類用於某個用戶的一般性信息.

.Net(不只是ASP.NET)中的安全機制基於負責人(principal)的概念,Principal對象代表以其名義運行代碼的用戶的安全
環境,因此,如果我運行程序,負責人就是程序運行期間我的安全環境。低於負責人的級別是身份(identity)
身份代表執行代碼的用戶。因此,每一個負責人都有一個身份,這種通用的負責人和身份的概念用於基於表單
的驗證。Windows驗證,甚至在.Net編程的其他用於傳遞證書給Web站點和遠程主機.我們決定不創建自己的安全系統
但是要使用自己的負責人和身份的概念,以便巧妙地吻合於Microsoft已有的安全體系..

以上引用《ASP.NET Web站點高級編程 提出問題-設計方案-解決方案》,以下簡稱ThePhile(工程名)

ThePhile的驗證方式是實現了IPrincipal和Identity接口


HttpContext.User的對象必須實現 System.Security.Principal.Iprincipal接口.

IPrincipal 概述

公共屬性
Identity 獲取當前用戶的標識。

公共方法
IsInRole 確定當前用戶是否屬於指定的角色。

公共屬性Identity又必須實現System.Security.Principal.IIdentity 接口

IIdentity 概述

公共屬性
AuthenticationType 獲取所使用的身份驗證的類型。
IsAuthenticated 獲取一個值,該值指示是否驗證了用戶。
Name 獲取當前用戶的名稱

只要實現了這IPrincipal和IIdentity兩個接口.然後分配給HttpContext.User的對象.
就可以判斷出是否驗證過.IsAuthenticated.或者獲取用戶名稱等.


在ThePhile工程中。繼承IPrincipal接口的是PhilePrincipal類(通過HttpContext.User可用)
繼承IIdentity接口的是SiteIdentity類(通過HttpContext.User.Identity可用)
注:偶手裏的代碼此類是叫SiteIdentity。而書上的是PhileIdentity。其實沒什麼只是個類名.


先來看看登錄頁位於ModulesUserLogin.aspx

這中登錄頁的登陸按鈕單擊事件


private void Submit_Click(object sender, System.EventArgs e)
        {           
            PhilePrincipal newUser = PhilePrincipal.ValidateLogin( EmailAddress.Text, Password.Text );
            //這裏驗證用戶.並實現IPrincipal和IIdentity接口
           
            if (newUser == null)
            {
                LoginResult.Text = "Login failed for " + EmailAddress.Text;
                LoginResult.Visible = true;
            }
            else
            {
                Context.User = newUser;
                FormsAuthentication.SetAuthCookie( EmailAddress.Text, true );                   
                Response.Redirect("/ThePhile/default.aspx");
                //登錄成功、寫Cookie。跳轉
            }
        }


###修改用戶接口來支持驗證.
需要修改PhilePage類。
因爲此類是Web頁的基類.. 繼承System.Web.UI.Page



using System;
using System.Web;
using System.Web.UI;
using System.Diagnostics;
using Wrox.WebModules;

using Wrox.WebModules.Accounts.Business;

namespace Wrox.ThePhile.Web
{
    /**//// <summary>
    /// Summary description for PhilePage.
    /// </summary>
    public class PhilePage : System.Web.UI.Page
    {               
        public PhilePage()
        {
        }

        protected override void OnInit(EventArgs e)
        {
            //這裏重寫了OnInit方法
            base.OnInit(e);
            this.Load += new System.EventHandler(this.PhilePage_Load);
            this.Error += new System.EventHandler(this.PhilePage_Error);
        }
           
        /**////這個是寫事件日誌方法
        protected void LogEvent(string message, EventLogEntryType entryType)
        {
            if (!EventLog.SourceExists("ThePhile.COM"))
            {
                EventLog.CreateEventSource("ThePhile.COM", "Application");
            }
            EventLog.WriteEntry("ThePhile.COM", message, entryType);
        }
       
        /**//// <summary>
        /// 捕獲錯誤顯示
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void PhilePage_Error(object sender, System.EventArgs e)
        {
            string errMsg;
            Exception currentError = Server.GetLastError();

            errMsg = "<link rel="stylesheet" href="/ThePhile/Styles/ThePhile.CSS">";
            errMsg += "<h1>Page Error</h1><hr/>An unexpected error has occurred on this page. The system " +
                "administrators have been notified. Please feel free to contact us with the information " +
                "surrounding this error.<br/>"+
                "The error occurred in: "+Request.Url.ToString()+"<br/>"+
                "Error Message: <font class="ErrorMessage">"+ currentError.Message.ToString() + "</font><hr/>"+
                "<b>Stack Trace:</b><br/>"+
                currentError.ToString();

            if ( !(currentError is AppException) )
            {
                // It is not one of ours, so we cannot guarantee that it has been logged
                // into the event log.
                LogEvent( currentError.ToString(), EventLogEntryType.Error );
            }

            Response.Write( errMsg );
            Server.ClearError();
        }

       
        private void PhilePage_Load(object sender, System.EventArgs e)
        {
            // TODO: Place any code that will take place BEFORE the Page_Load event
            // in the regular page, e.g. cache management, authentication verification,
            // etc.                                           
            if (Context.User.Identity.IsAuthenticated)
            {
                        //如果是驗證通過的
                   
                if (!(Context.User is PhilePrincipal))
                {
                    // ASP.NET's regular forms authentication picked up our cookie, but we
                    // haven't replaced the default context user with our own. Let's do that
                    // now. We know that the previous context.user.identity.name is the e-mail
                    // address (because we forced it to be as such in the login.aspx page)               
                    PhilePrincipal newUser = new PhilePrincipal( Context.User.Identity.Name );
                    Context.User = newUser;
                }
                //此處是當前的Context.User不是PihlePrincipal的。轉換一下
                //再賦給Context.User
            }
        }
   
    }
}

上面是PhilePage類。在Web頁調用時繼承一下就行了
此處有一個問題。當ASPX頁繼承此類時。
Web 窗體設計器生成的代碼#region Web 窗體設計器生成的代碼
        override protected void OnInit(EventArgs e)
        {
            //
            // CODEGEN: 該調用是 ASP.NET Web 窗體設計器所必需的。
            //
            InitializeComponent();
            base.OnInit(e);
        }
       
        /**//// <summary>
        /// 設計器支持所需的方法 - 不要使用代碼編輯器修改
        /// 此方法的內容。
        /// </summary>
        private void InitializeComponent()
        {   
            this.Load += new System.EventHandler(this.Page_Load);
        }
        #endregion

請看OnInit方法。是選調用了InitializeComponent()後調用父類的base.OnInit(e)
呵。這裏可折騰了好幾天。如果這樣的話就在頁面載入是先調用的是本頁的Page_Load()方法
後調用父類的OnInit(e),這樣PhilePage的Phile_Load()就形同虛設了。
在Thephile工程中它的頁面的OnInit都是base.OnInit(e)在前面.而如果你新建一個頁面的話就是在後面了
這可能與.Net版本有關。在書的封面上有Writeen and tested for final release of .Net V1.0
我這沒有.Net v1.0所以也無法測試了。所以現在用2003 Vs.Net 的IDe時新建的頁想要繼承PhilePage需要把這兩個方法的默認順序手動改一下.

再看siteHeader控件.是通過驗證顯示用戶名相關信息。否則顯示未登錄信息


private void Page_Load(object sender, System.EventArgs e)
        {
            // Put user code to initialize the page here
            Greeting.Text = "Welcome, ";
            /**////是否驗證過
            if (Context.User.Identity.IsAuthenticated)
            {
                Greeting.Text += "<b>" + Context.User.Identity.Name + "</b>";
                UserLink.Text = "My Account";
                UserLink.NavigateUrl = "/ThePhile/Modules/Users/MyAccount.aspx";
                SignOut.Visible = true;
            }
            else
            {
                Greeting.Text += "Guest User.";
                UserLink.Text = "Click to Login";
                UserLink.NavigateUrl = "/ThePhile/Modules/Users/Login.aspx";
                SignOut.Visible = false;
            }       
        }
            /**////這是退出
        private void SignOut_Click(object sender, System.EventArgs e)
        {
            FormsAuthentication.SignOut();
            Response.Redirect("/thephile");
        }
這樣就實現了登錄驗證。這裏一定要注意的地方是。呵要先啓用Forms驗證方可使上面的代碼奏效


<identity impersonate="true" />
    <!--  AUTHENTICATION
          This section sets the authentication policies of the application. Possible modes are "Windows", "Forms",
          "Passport" and "None"
    -->
    <authentication mode="Forms">
        <forms name="ThePhile" path="/" loginUrl="/ThePhile/Modules/Users/Login.aspx"
            protection="All" timeout="30">
        </forms>
    </authentication>



具體的代碼請參看ThePhile.早就應該寫了。出於自己懶。一看12月快過了一個隨筆都沒有可不行。
急急忙瞎寫了一大堆。有錯誤和不妥地方請大家見諒!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章