小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

asp.net Forms表單驗證 使用經(jīng)驗及驗證流程分析

 仰望//45度微笑 2012-03-31

      最近,要做一個登陸的頁面,就想到了安全性方面的問題。記得曾經(jīng)在邵志東老師講的關(guān)于asp.net安全性方面的課程中,提到asp.net提供了4個身份驗證程序:1.表單身份驗證;2.Windows身份驗證;3.Passport身份驗證;4.默認身份驗證。尤其講了表單身份驗證,想想,正好自己以前也不曾使用過這個驗證方式,那就拿來練練手吧。

      表單驗證,可以根據(jù)用戶和角色來限制用戶訪問。比如,我們有以一個后臺管理系統(tǒng),只有通過后臺登陸頁面合法登陸的用戶才能訪問后臺管理系統(tǒng)中的任何頁面,這個時候我們就可以通過表單驗證來實現(xiàn)(過去我都是在每一個頁面寫判斷邏輯。現(xiàn)在想起來,過去的那種方法真是不折不扣的體力勞動,而且如果哪個頁面忘記寫了,就麻煩了)。

      實驗開始(因為只記錄經(jīng)驗,所以有些知識點這里并沒有提到,需要大家多花點課外時間了。文末提供了些鏈接供大家參考)

      我接下來就來做一個Forms表單驗證的例子。在該例子中,我建立了兩個文件夾分別為User和Admin,在每一個文件夾中又有l(wèi)ogin.aspx、index.aspx和web.config。我希望普通用戶訪問User文件夾需要首先要在用戶登陸界面進行登陸,成功后才能訪問用戶的index.aspx。而管理員則首先要在Admin的登陸界面進行登陸,才能訪問Admin中的index.aspx。而在網(wǎng)站根目錄有LoginRedirect.aspx、web.config和Global.asax。
      目錄結(jié)構(gòu)圖:

      

      如何才能實現(xiàn)表單驗證呢?
      1.配置根目錄下的web.config (在網(wǎng)站根目錄下web.config文件中的system.web標記中,修改原<authentication mode="Windows" />為如下代碼)


        <authentication mode="Forms">
            
<forms name="adminlogin" loginUrl="loginRedirect.aspx">
            
</forms>
        
</authentication>
        
<authorization>
            
<allow users="*"/>
        
</authorization>

      上述的配置是什么意思呢?
      首先,這里有兩個不同的配置節(jié),authentication和authorization看上去是不是很像? 你可千萬不要被眼睛欺騙了,這兩個是不同的意思,前者是“驗證”,后者是“授權(quán)”。
      接著,我們來看下“驗證”這個配置節(jié)中的東西。
      mode表示的就是驗證方式,這里有四個選項:Windows、Forms、Passport、None。默認的是Windows。我們這里選擇Forms。
      而在forms元素里,設置了name和loginUrl。
      name表示cookie的名字,我們后面要通過cookie來保存一些用戶信息并將包含cookie信息的http請求發(fā)送到服務器。服務器端,則會根據(jù)cookie信息對用戶進行標識,從而進行進一步的驗證。
      LoginUrl 顧名思義就是登陸頁面的地址。如果說用戶沒有權(quán)限訪問某一頁面,就會被重定向到這個頁面。

      還有其它諸多元素,請大家自己查找相關(guān)資料。我也會在文末給出一些我認為比較不錯的鏈接。

      講完了“驗證”節(jié),接著講講“授權(quán)”節(jié)。
      授權(quán),自然是要限制哪些用戶或角色可以訪問,哪些用戶或角色不能訪問了。設置的方式就是通過設置<allow>和<deny>。如上所示的<allow users="*">就是表示允許所有用戶訪問。你可能會奇怪不是要限制用戶訪問嗎,怎么全部允許了?那是因為,我就是希望“根目錄下”的所有東西都可以被任何用戶訪問。

      再來看看兩個子文件夾內(nèi)的web.config。


<configuration>
  
<location path="login.aspx">
    
<system.web>
      
<authorization>
        <allow users="*"/>
      
</authorization>
    
</system.web>
  
</location>
  
<system.web>
    
<authorization>
      
<allow roles="user"/>
      
<deny users="*"/>
    
</authorization>
  
</system.web>
</configuration>


      在這個配置文件中,不能配置“驗證”節(jié)的內(nèi)容(該內(nèi)容只能在虛擬目錄的根目錄web.config中配置),我們只能對“授權(quán)”節(jié)進行配置。上述的location的作用是表示該路徑不需要進行授權(quán)檢查,因為我希望任何用戶都可以進到登陸頁面,原因大家應該都想得到吧。
      而其他路徑,則不希望未登陸的用戶或網(wǎng)站管理員登陸,因此使用<allow roles="user">來允許只有角色為user的用戶訪問,而其他任何用戶都拒絕訪問。
      同理,來看下管理員目錄的web.config,請大家自己分析。


<configuration>
  
<location path="login.aspx">
    
<system.web>
      
<authorization>
        
<allow users="*"/>
      
</authorization>
    
</system.web>
  
</location>
  
<system.web>
    
<authorization>
      
<allow roles="Manager"/>
      
<deny users="*"/>
    
</authorization>
  
</system.web>
</configuration>

      配置好了之后,我們還需要寫一些cs代碼。首先我們來看一下loginRedirect.aspx.cs。因為,我們現(xiàn)在訪問上述任何一個子文件的頁面時,都會先跳轉(zhuǎn)到這個頁面里來,而其實我則希望可以跳到相信子目錄的登陸頁面中去。因此,需要在這個文件中進行一些判斷。


string from = Request.QueryString["ReturnUrl"];//每個跳轉(zhuǎn)過來的頁面都會帶有ReturnUrl值,以此來獲取跳轉(zhuǎn)之前的頁面
//獲取子目錄名稱
string fromFilePath = from.Substring(from.IndexOf('/'+ 1, from.IndexOf('/', from.IndexOf('/'+ 1- from.IndexOf('/')-1);
//根據(jù)子目錄名稱來判斷跳轉(zhuǎn)的鏈接
switch (fromFilePath.ToLower())
{
    
case "admin": Response.Redirect("/admin/login.aspx"); break;
    
case "user": Response.Redirect("/user/login.aspx"); break;
}

       有些人可能奇怪了,這么麻煩,既然可以在“驗證”節(jié)中配置loginUrl,難道就不能對每個目錄實現(xiàn)直接跳轉(zhuǎn)到本目錄相應登陸頁面嗎?很遺憾,目前為止,我還沒有找到直接的解決辦法。如果您有什么辦法,請不吝賜教。
       跳轉(zhuǎn)到登陸頁面后,那我們就應該對用戶的登陸時間進行處理了。


protected void Page_Load(object sender, EventArgs e)
{
    
//判斷用戶是否已經(jīng)登陸,且角色為user
    if (User.Identity.IsAuthenticated&&User.IsInRole("user"))
     {
//如果通過驗證,則直接跳轉(zhuǎn)到index.aspx
        Response.Redirect("index.aspx");
     }
}

//登陸按鈕事件,這里簡單起見,我直接以用戶名"user",密碼"1"來判斷,當然你也可以從數(shù)據(jù)庫讀取。
protected void btnLogin_Click(object sender, EventArgs e)
{
    
if (tbUserName.Text == "user" && tbPwd.Text == "1")
     {
        
//生成驗證票據(jù),其中包括用戶名、生效時間、過期時間、是否永久保存和用戶數(shù)據(jù)等。而關(guān)于用戶角色的信息,我們保存在用戶數(shù)據(jù)中。
        FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, tbUserName.Text, DateTime.Now, DateTime.Now.AddMinutes(30), true"User");
        
string cookieStr = FormsAuthentication.Encrypt(ticket);//對票據(jù)進行加密
        HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, cookieStr);
/*保存到cookie中。cookie的名字要與我們前面在配置文件中所寫的name值一樣。因為,當cookie保留在本地后,下次再檢查用戶權(quán)限的時候就會自動查找與forms名稱相同的cookie,并傳送給服務器端進行檢驗。如果在本地找不到cookie,就自然無法通過驗證。*/
        cookie.Expires 
= ticket.Expiration;
         cookie.Path 
= FormsAuthentication.FormsCookiePath;
         Response.Cookies.Add(cookie);
         Response.Redirect(
"index.aspx");//登陸成功后跳轉(zhuǎn)到index.aspx
    }
}
/*
這里突然冒出一個票據(jù),有些朋友是不是很奇怪呀?票據(jù)什么用呢?
票據(jù)其實也可以理解為憑據(jù)(只有有憑據(jù)的用戶才能通過檢查),它包括了上面注釋中所寫的一些與用戶相關(guān)的信息。但是票據(jù)不能直接傳送給服務器必須通過cookie來承載。而服務器端在接受到cookie之后,會從中取出票據(jù)的數(shù)據(jù),并進行相關(guān)操作。
*/

      在Admin文件夾下的login.aspx.cs也是類似。就不再贅述了。
      差點忘了最后的一個東西了,就是為我們的用戶配置角色。上面我們在創(chuàng)建票據(jù)的時候發(fā)現(xiàn)沒有提供直接對角色賦值的功能,那我們就只能利用grobal.asax來實現(xiàn)了。
      在global.asax中有一個Application_AuthenticateRequest事件,該事件會在服務器決定該用戶瀏覽器是否應該跳轉(zhuǎn)前發(fā)生。因此,我們只要在這里對用戶角色進行配置,就可以達到目的。


protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    
if (HttpContext.Current.User != null)
     {
//如果用戶通過驗證,則該項不為null
        if (HttpContext.Current.User.Identity.IsAuthenticated)
         {
            
if (HttpContext.Current.User.Identity is FormsIdentity)
             {
                 FormsIdentity id 
= (FormsIdentity)HttpContext.Current.User.Identity;
                 FormsAuthenticationTicket ticket 
= id.Ticket;

                
string userData = ticket.UserData;//取出角色數(shù)據(jù)
                string[] roles = userData.Split(',');
                 HttpContext.Current.User 
= new GenericPrincipal(id, roles);//重新分配角色
            }
         }
     }
}

      大家可以下載整個工程來看。
      【注意:不能在同一臺電腦上即登陸用戶界面又登陸管理員界面。因為使用Forms名稱所能保留的cookie只可能是一個,所以如果登陸了管理員界面后,接著登陸用戶界面,就會覆蓋原來的cookie值。有些朋友使用session來保存用戶數(shù)據(jù)的方法,為實驗。】
      實驗結(jié)束


      Forms驗證流程
      大致頁面處理流程如下:(介紹這個是為了引出FormsAuthenticationModule,因此不詳細介紹,大家可以參考:ASP.NET頁面生成流程
      客戶端的http請求到達服務器端后,首先IIS會接收到該消息,然后調(diào)用asp.net isapi擴展,并由該擴展將請求等信息傳送給.net運行時。.Net Runtime會調(diào)用ProcessRequest方法根據(jù)客戶端發(fā)來的請求信息創(chuàng)建并初始化一個HttpWorkerRequest對象,并根據(jù)該對象創(chuàng)建HttpContext對象,該對象中包含HttpRequest、HttpResponse對象,其中HttpRequest對象中又包含cookie和瀏覽器信息。最終會生成并調(diào)用HttpApplication對象的Init方法。在Init方法中會調(diào)用HttpApplicaion.InitInternal方法。而該方法又會調(diào)用InitModules方法。InitModules方法則會初始化Web.Config中注冊的所有模塊(HttpModule)。

      我們的主角FormsAuthenticationModule也就是在這里上場了。
      初始化FormsAuthenticationModule的過程中,會先調(diào)用該Module的init方法。我們來看一下該方法中有些什么:

public void Init(HttpApplication app)
{
     app.AuthenticateRequest 
+= new EventHandler(this.OnEnter);
     app.EndRequest 
+= new EventHandler(this.OnLeave);
}

       Init方法注冊了兩個事件:OnEnter和OnLeave。分別在HttpApplication.AuthenticateRequest和EndRequst事件被觸發(fā)時執(zhí)行。
      這兩個事件具體做了些什么呢? 

private void OnEnter(object source, EventArgs eventArgs)
{
    
if (!_fAuthChecked || _fAuthRequired)
     {
         HttpApplication application 
= (HttpApplication) source;
         HttpContext context 
= application.Context;
         Trace(
"*******************Request path: " + context.Request.PathWithQueryString);
     
//從Web.Config中獲取authentication配置信息
        AuthenticationSection authentication = RuntimeConfig.GetAppConfig().Authentication;
         authentication.ValidateAuthenticationMode();
        
if (!_fAuthChecked)
         {

            
//設置是否為Forms驗證,如果是_fAuthRequired 設為true
            _fAuthRequired = authentication.Mode == AuthenticationMode.Forms;
             _fAuthChecked 
= true;
         }
        
if (_fAuthRequired)
         {
            
if (!this._fFormsInit)
             {
                 Trace(
"Initializing Forms Auth Manager");
                
//初始化驗證信息,Initialize方法主要是通過讀取配置文件的authentication節(jié)來初始化FormsName、LoginUrl等
                FormsAuthentication.Initialize();
                
this._FormsName = authentication.Forms.Name;
                
if (this._FormsName == null)
                 {
                    
this._FormsName = ".ASPXAUTH";
                 }
                 Trace(
"Forms name is: " + this._FormsName);
                
this._LoginUrl = authentication.Forms.LoginUrl;
                
if (this._LoginUrl == null)
                 {
                    
this._LoginUrl = "login.aspx";
                 }
                
this._fFormsInit = true;
             }
            
//以下方法用于設置通過驗證的用戶標識[重要]
            this.OnAuthenticate(new FormsAuthenticationEventArgs(context));
             CookielessHelperClass cookielessHelper 
= context.CookielessHelper;
            
//下面的語句,應該是為了修改_skipAuthorization.該值指定 UrlAuthorizationModule 對象是否應跳過對當前請求的授權(quán)檢查。
     
//Forms 身份驗證模塊和 Passport 身份驗證模塊在重定向到已配置的登錄頁時都設置 SkipAuthorization。[MSDN]
     
//如果為false則要進行授權(quán)檢查,否則就跳過檢查。[我的體會:如果不在代碼上進行控制,一般該值都為false。]
            if (AuthenticationConfig.AccessingLoginPage(context, this._LoginUrl))
             {   
                 context._skipAuthorization 
= true;
                 cookielessHelper.RedirectWithDetectionIfRequired(
null, FormsAuthentication.CookieMode);
             }
            
if (!context.SkipAuthorization)
             {
                 context._skipAuthorization 
= AssemblyResourceLoader.IsValidWebResourceRequest(context);
             }
         }
     }
}

      在OnEnter事件中,我們提到一個重要的方法就是OnAuthenticate:

//通過這個方法,我們就可以得到一個通過驗證User標識
private void OnAuthenticate(FormsAuthenticationEventArgs e)
{
     HttpCookie cookie 
= null;
   
//_eventHandler是一個FormsAuthenticationModule類的Authenticate事件??梢酝ㄟ^在asp.net應用程序的Global.asax文件中進行處理
    if (this._eventHandler != null)
     {
        
this._eventHandler(this, e);
     }
  
//判斷用戶是否已經(jīng)通過驗證,如果已經(jīng)通過驗證則方法結(jié)束。通過驗證的用戶,其User標識不為Null。
    if ((e.Context.User != null|| (e.User != null))
     {
        
if (e.Context.User == null)
         {
             e.Context._user 
= e.User;
         }
     }
    
else
     {   
         FormsAuthenticationTicket tOld 
= null;
        
bool cookielessTicket = false;
        
try
         {  
            
//從Cookie數(shù)據(jù)中提取驗證票據(jù)的數(shù)據(jù)
            tOld = ExtractTicketFromCookie(e.Context, this._FormsName, out cookielessTicket);
         }
        
catch
         {
             tOld 
= null;
         }
        
if ((tOld != null&& !tOld.Expired)
         {  
            FormsAuthenticationTicket ticket 
= tOld;
            
if (FormsAuthentication.SlidingExpiration)
             {

              
//更新驗證票據(jù),根據(jù)所設置的過期時間來判斷
                ticket = FormsAuthentication.RenewTicketIfOld(tOld);
             }
            
//根據(jù)票據(jù)信息來創(chuàng)建用戶標識。第二個參數(shù)是用于對用戶授于某種角色用的,但是從new string[0]可以看出此處不含角色數(shù)據(jù)。
     
//如果我們需要對用戶的角色進行配置,可以在FormsAuthenticationModule類的Authenticate事件中配置
            e.Context._user = new GenericPrincipal(new FormsIdentity(ticket), new string[0]);
            
if (!cookielessTicket && !ticket.CookiePath.Equals("/"))
             {
                 cookie 
= e.Context.Request.Cookies[this._FormsName];
                
if (cookie != null)
                 {
                     cookie.Path 
= ticket.CookiePath;
                 }
             }
     
//如果票據(jù)是新的,則生成一個新的Cookie給客戶端
            if (ticket != tOld)
             {
                
if ((cookielessTicket && (ticket.CookiePath != "/")) && (ticket.CookiePath.Length > 1))
                 {
                     ticket 
= new FormsAuthenticationTicket(ticket.Version, ticket.Name, ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, ticket.UserData, "/");
                 }
                
string cookieValue = FormsAuthentication.Encrypt(ticket);
                
if (cookielessTicket)
                 {
                     e.Context.CookielessHelper.SetCookieValue(
'F', cookieValue);
                     e.Context.Response.Redirect(e.Context.Request.PathWithQueryString);
                 }
                
else
                 {
                    
if (cookie != null)
                     {
                         cookie 
= e.Context.Request.Cookies[this._FormsName];
                     }
                    
if (cookie == null)
                     {
                         cookie 
= new HttpCookie(this._FormsName, cookieValue);
                         cookie.Path 
= ticket.CookiePath;
                     }
                    
if (ticket.IsPersistent)
                     {
                         cookie.Expires 
= ticket.Expiration;
                     }
                     cookie.Value 
= cookieValue;
                     cookie.Secure 
= FormsAuthentication.RequireSSL;
                     cookie.HttpOnly 
= true;
                    
if (FormsAuthentication.CookieDomain != null)
                     {
                         cookie.Domain 
= FormsAuthentication.CookieDomain;
                     }
                     e.Context.Response.Cookies.Add(cookie);
                 }
             }
         }
     }
}

      在執(zhí)行了這個module之后,還有一個重要的module我們不得不提的就是UrlAuthorizationModule。在這個module中,對上面所設置的用戶進行了授權(quán)檢查,來確定該用戶是否可以訪問所請求的頁面。如果用戶沒有權(quán)限,則跳轉(zhuǎn)到loginUrl中所指定的頁面。主要方法就是OnEnter:

private void OnEnter(object source, EventArgs eventArgs)
{
     HttpApplication application 
= (HttpApplication) source;
     HttpContext context 
= application.Context;
    
if (context.SkipAuthorization)
     {
        
if (!context.User.Identity.IsAuthenticated)
         {
             PerfCounters.IncrementCounter(AppPerfCounter.ANONYMOUS_REQUESTS);
         }
     }
    
else
     {
        
//讀取web.config中配置的授權(quán)信息
        AuthorizationSection authorization = RuntimeConfig.GetConfig(context).Authorization;
        
//IsUserAllowed便是對用戶進行授權(quán)檢查
        if (!authorization.EveryoneAllowed && !authorization.IsUserAllowed(context.User, context.Request.RequestType))
         {
             context.Response.StatusCode 
= 0x191;//用戶沒有被授權(quán),[記住這個標識]
            this.WriteErrorMessage(context);
            
if (context.User.Identity.IsAuthenticated)
             {
                 WebBaseEvent.RaiseSystemEvent(
this0xfa7);
             }
             application.CompleteRequest();
         }
        
else
         {
            
if (!context.User.Identity.IsAuthenticated)
             {
                 PerfCounters.IncrementCounter(AppPerfCounter.ANONYMOUS_REQUESTS);
             }
             WebBaseEvent.RaiseSystemEvent(
this0xfa3);
         }
     }
}

      前面我們介紹了,F(xiàn)ormsAuthenticationModule中的2個主要事件中注冊了2個方法。這里來說第二個OnLeave方法。在這個方法中才真正設置了跳轉(zhuǎn)的頁面。

private void OnLeave(object source, EventArgs eventArgs)
{
    
if (_fAuthChecked && _fAuthRequired)
     {
         HttpApplication application 
= (HttpApplication) source;
         HttpContext context 
= application.Context;
        
//如果標識為0x191,則跳轉(zhuǎn)到loginUrl
        if (context.Response.StatusCode == 0x191)
         {
            
string str3;
            
string strUrl = null;
            
if (!string.IsNullOrEmpty(this._LoginUrl))
             {
                 strUrl 
= AuthenticationConfig.GetCompleteLoginUrl(context, this._LoginUrl);
             }
            
if ((strUrl == null|| (strUrl.Length <= 0))
             {
                
throw new HttpException(SR.GetString("Auth_Invalid_Login_Url"));
             }
             CookielessHelperClass cookielessHelper 
= context.CookielessHelper;
            
string pathWithQueryString = context.Request.PathWithQueryString;
            
if (strUrl.IndexOf('?'>= 0)
             {
                 str3 
= FormsAuthentication.RemoveQueryStringVariableFromUrl(strUrl, "ReturnUrl"+ "&ReturnUrl=" + HttpUtility.UrlEncode(pathWithQueryString, context.Request.ContentEncoding);
             }
            
else
             {
                 str3 
= strUrl + "?ReturnUrl=" + HttpUtility.UrlEncode(pathWithQueryString, context.Request.ContentEncoding);
             }
            
int index = pathWithQueryString.IndexOf('?');
            
if ((index >= 0&& (index < (pathWithQueryString.Length - 1)))
             {
                 pathWithQueryString 
= FormsAuthentication.RemoveQueryStringVariableFromUrl(pathWithQueryString, "ReturnUrl");
             }
             index 
= pathWithQueryString.IndexOf('?');
            
if ((index >= 0&& (index < (pathWithQueryString.Length - 1)))
             {
                 str3 
= str3 + "&" + pathWithQueryString.Substring(index + 1);
             }
             cookielessHelper.SetCookieValue(
'F'null);
             cookielessHelper.RedirectWithDetectionIfRequired(str3, FormsAuthentication.CookieMode);
             context.Response.Redirect(str3, 
false);
         }
     }
}

      根據(jù)這個流程,結(jié)合前面的實驗,我們來模擬以下這個執(zhí)行過程。
      下述a~o這些步驟大致描述了整個驗證的執(zhí)行流程。其中涉及到一些Http協(xié)議的知識:(這里介紹幾個)
      每次我們請求一個頁面,就是在發(fā)送一個http請求。在這個請求中包含了我們請求的方式(主要是Get、Post)、請求的頁面地址、客戶端的瀏覽器信息、Cookie等。而發(fā)送一次請求之后,服務器都會返回一個Http應答包。在這個包中會有一些表示狀態(tài)的代碼,比如我們常見的404、200等,而表示跳轉(zhuǎn)的狀態(tài)代碼則是302。另外,如果服務器需要在客戶端設置cookie的話會在應答包的包頭中加入set-cookie。具體例子如下:



上圖為一次Http請求 

 


上圖為一次Http應答


      對Http協(xié)議有所了解后,現(xiàn)在來假設是第一次訪問用戶文件夾中的index.aspx頁面。那這個過程就如下所示:
      a.由于是第一次訪問這個站點,瀏覽器無法在本地找到與這個網(wǎng)站對應的cookie,因此會發(fā)送一個cookie為空的http請求到服務器端。
      b.服務器的IIS在接受到此請求后,會交給asp.net isapi擴展進行處理。.net 運行時會為這個請求創(chuàng)建一個HttpApplication對象。
      c.HttpApplication對象創(chuàng)建后,會執(zhí)行Init()方法,從而執(zhí)行了FormsAutheticationModule。
      d.在執(zhí)行該模塊的過程中首先會讀取web.config中的配置信息配置loginUrl等數(shù)據(jù)。
      e.接著會觸發(fā)OnAuthenticate方法,該方法首先執(zhí)行g(shù)loabl.aspx中的Application_AuthenticateRequest事件,不過往往由于此時用戶還并未通過驗證,所以在這次請求中,前面global.asax所寫的內(nèi)容執(zhí)行不到。接著就會檢查用戶是否通過驗證,本次請求顯然是沒有通過驗證。
      f.在UrlAuthorizationModule中,首先從web.config中讀取配置信息,然后核對用戶。由于e中用戶沒有通過驗證,因此這里肯定核對失敗。于是會執(zhí)行context.Response.StatusCode = 0x191。
      g.最后執(zhí)行到FormsAutheticationModule的OnLeave事件,因為context.Response.StatusCode == 0x191所以設置用戶瀏覽器需要執(zhí)行跳轉(zhuǎn)。這個實現(xiàn)的方式,是通過http應答包返回302指令(跳轉(zhuǎn)指令),并設置了http頭的Location為目的頁面。
      h.瀏覽器在接受到返回的http應答包后,執(zhí)行跳轉(zhuǎn)。此時目標為LoginRedirect.aspx。(同樣有是一次對loginredirect.aspx的請求,過程省略)。
      i .由于我們在LoginRedirect.aspx.cs中也是一個跳轉(zhuǎn),因此請求這個頁面所返回的Http應答包同樣是一個跳轉(zhuǎn)指令(跳轉(zhuǎn)到用戶登陸的界面Login.aspx)。
      j .輸入用戶名,密碼單擊登陸,又發(fā)送了一次http請求到服務器端。但是這次包含了用戶的登陸數(shù)據(jù)是按Post方式發(fā)送的。
      k.由于此時用戶并沒有審核通過,所以仍舊執(zhí)行上面的a~d,由于login.aspx這個頁面在配置文件中我們是設置為[location]節(jié)中,因此在后面的驗證中就是一路綠燈呀。執(zhí)行完了所有module后的,此時的http應答包中并不包含跳轉(zhuǎn)指令。
      l.接著執(zhí)行在login.aspx.cs中定義的事件,在該事件中,對用戶的登陸信息進行驗證,如果驗證通過,則設置驗證票據(jù),并將其值保存在cookie中,同時在http應答包中加入cookie。也就是執(zhí)行Response.Cookie.Add(); 并且,還在事件最后要求瀏覽器跳轉(zhuǎn)到index.aspx。這便又在http應答包中加入了跳轉(zhuǎn)指令。
      m.瀏覽器在接收到這個http應答包后,提取其中的cookie,并保存在本地。同時跳轉(zhuǎn)到相應頁面(又發(fā)起一次對index.aspx頁面的請求)。
      n.在新的請求發(fā)出之前,瀏覽器由于找到了該站點對應的cookie,會把該cookie值加入到請求中發(fā)送到服務器。
      o.后續(xù)的步驟其實又執(zhí)行了一遍上述過程,但是這次在驗證的時候,因為有了傳入的cookie,可以得到合法用戶的信息,也就通過了驗證。

      流程介紹結(jié)束

      寫的不當之處,希望大家直言不諱~~

      整個工程下載http://files.cnblogs.com/stg609/LoginAuthentication.rar(開發(fā)平臺:VS 2008. 不過,基本沒用到.net 3.0的東西,可能可以順利轉(zhuǎn)換到VS 2005上使用)

      推薦閱讀http://www.cnblogs.com/cuihongyu3503319/archive/2008/09/11/1288956.html
                     http://book.csdn.net/bookfiles/406/10040614811.shtml
                     http://www./KB/web-security/formsroleauth.aspx
                     http://blog.csdn.net/virone/archive/2008/04/12/2284173.aspx
                     手把手教你HTTP協(xié)議之Session和Cookie

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多