|
本篇的話題如下:
Forms驗(yàn)證的工作原理
Forms驗(yàn)證中的API
Forms驗(yàn)證的工作原理
我們知道,F(xiàn)orms驗(yàn)證主要是基于cookie的,說(shuō)白一點(diǎn)就是:把用戶信息保存在cookie中,然后發(fā)送到客戶端;再就是解析客戶端的發(fā)送了的cookie信息,進(jìn)行解析,然后進(jìn)行驗(yàn)證。關(guān)于cookieless的工作原理和方法,我這里不贅述,大家可以參看我的另外的一片文章:淺談ASP.NET內(nèi)部機(jī)制(一)。
當(dāng)匿名用戶請(qǐng)求一個(gè)需要驗(yàn)證后才能訪問(wèn)的資源和頁(yè)面的時(shí)候,那么如果采用了Forms驗(yàn)證,那么URL授權(quán)模塊就會(huì)把用戶重定向到登錄頁(yè)面。而之前請(qǐng)求的URL就會(huì)被保存起來(lái),等到用戶正確的登錄后,就再次轉(zhuǎn)向之前要請(qǐng)求的頁(yè)面。我想這點(diǎn),大家應(yīng)該都用過(guò)。
下面我們就看看登錄的時(shí)候發(fā)生了什么,看看登錄的具體的流程?也請(qǐng)大家注意我使用的一些術(shù)語(yǔ),因?yàn)檫@些術(shù)語(yǔ)再Forms中都有特定的對(duì)象,大家之后就可以看到的,很重要。
1.再瀏覽器中有個(gè)登錄窗體,要輸入用戶名和密碼等憑證,通過(guò)提交給服務(wù)器的ASP.NET網(wǎng)站來(lái)審核,檢查憑證是否正確。
2.如果憑證正確,那么就會(huì)再服務(wù)器端就會(huì)創(chuàng)建一個(gè)"身份驗(yàn)證票據(jù)"。身份驗(yàn)證票據(jù)中含有了經(jīng)過(guò)加密的用戶信息。
3.這個(gè)票據(jù)再服務(wù)器端被寫入cookie中,然后發(fā)送到客戶端。
4.然后用戶就被重定向到他們最初請(qǐng)求的URL中。
注:大家可能會(huì)有疑問(wèn):最初請(qǐng)求的URL到底保存在哪里?不要擔(dān)心,現(xiàn)在只要明白上面的流程就OK。
5.上面第4步就是要轉(zhuǎn)向最初請(qǐng)求的URL,假設(shè)最初的請(qǐng)求頁(yè)面是Default.ASPx,那么現(xiàn)在就是從登錄的頁(yè)面Login.ASPx轉(zhuǎn)向到Default.ASPx 頁(yè)面,此時(shí)因?yàn)樯矸蒡?yàn)證的票據(jù)cookie已經(jīng)存在于客戶端的瀏覽器中了,此時(shí)的轉(zhuǎn)向Default.ASPx頁(yè)面時(shí),實(shí)際是再次向服務(wù)器端發(fā)起了請(qǐng)求,所以正如我們之前所談到的:每個(gè)請(qǐng)求都要從ASP.NET管道中一級(jí)級(jí)的向后傳,要經(jīng)歷ASP.NET的的生命周期:Application_BeginRequest,Application_AuthenticateRequest.....。(希望大家明白)
但是這次的請(qǐng)求就和第一次我們發(fā)起的請(qǐng)求步同了,為什么?
第一次我們請(qǐng)求Default.ASPx頁(yè)面的時(shí)候,我們根本就沒(méi)有提供任何的表明我們身份的票據(jù),但是這次我們已經(jīng)登錄了,而且我們的瀏覽器中已經(jīng)有了我們的身份驗(yàn)證的票據(jù)的cookie,此時(shí)在Application_AuthenticateRequest事件中,F(xiàn)orms驗(yàn)證模塊就獲取表明我們身份cookie,然后就利用cookie中信息填充Context.User。
驗(yàn)證模塊處理完之后就是授權(quán)模塊起作用了。其實(shí)URL授權(quán)模塊就會(huì)利用我們之前填充在Context.User中的信息來(lái)驗(yàn)證用戶是否被批準(zhǔn)訪問(wèn)所請(qǐng)求的資源或者頁(yè)面。
Forms驗(yàn)證中的API
實(shí)現(xiàn)Forms身份驗(yàn)證之前,我們看看組成Forms驗(yàn)證的API以及相關(guān)的類:
FormsAuthenticationModule:對(duì)每個(gè)請(qǐng)求進(jìn)行驗(yàn)證的HTTP模塊
FormsAuthentication:包含在Forms驗(yàn)證中我們常用的方法和屬性(很重要的)
FormsIdentity:Forms驗(yàn)證標(biāo)識(shí)。
FormsAuthenticationTicket:身份驗(yàn)證的票據(jù),對(duì)用戶的信息進(jìn)行加密后的產(chǎn)物,我們一般把它寫如cookie中,之前我們談過(guò)了的。
上面的類在System.Web.Security下。
下面我們來(lái)一一介紹.
FormsAuthenticationModule
它是一個(gè)實(shí)現(xiàn)了IHttpModule接口的類。它可以用來(lái)處理每個(gè)請(qǐng)求的Application_AuthenticateRequest事件。如果發(fā)送了的請(qǐng)求中已經(jīng)包含了cookie信息,那么這個(gè)模塊就對(duì)cookie信息進(jìn)行解密和解析,然后構(gòu)造一個(gè)GenericPrincipal的類實(shí)例填充Context.User,并且也創(chuàng)建一個(gè)FormsIdentity的實(shí)例。
注意:當(dāng)我們?cè)趙eb.config中配置了Forms驗(yàn)證后,那么我們?cè)贏pplication_AuthenticateRequest事件寫的代碼要是和Forms相關(guān)的API。上篇文章談過(guò)了。
FormsAuthentication類這個(gè)類很重要。
還有一點(diǎn)注意的就是:因?yàn)镕ormsAuthentication和FormsAuthenticationModule名稱很相似,很容易混淆。
它們之前的區(qū)別在于,F(xiàn)ormsAuthenticationModule是一個(gè)HTTP模塊;而FormsAuthenticate是一個(gè)類,它有很多的方法和屬性。更加直白的說(shuō)就是:它們之前沒(méi)有什么關(guān)聯(lián),只是在Application_AuthenticateRequest事件中我們常常要調(diào)用FormsAuthenticate類的一些方法和屬性。而且FormsAuthenticate的很多方法都是靜態(tài)的方法,我們不會(huì)創(chuàng)建FormsAuthenticate類的實(shí)例。
還有一點(diǎn)要特別注意的就是FormsAuthenticate的Authenticate方法。
我們之前說(shuō)過(guò)了,我們一般是在登錄窗體中提交用戶信息,然后服務(wù)器端驗(yàn)證提交的信息,我們?cè)?a href=/yuedu/fuwuqi/ target=_blank class=infotextkey>服務(wù)器端常常是去數(shù)據(jù)庫(kù)中檢查這些信息的正確性,但是去數(shù)據(jù)庫(kù)或者其他的數(shù)據(jù)存儲(chǔ)(如文件,活動(dòng)目錄)中去檢查只是一種情況。
還有另外的情況。不知道大家是否記得web.config 中的一個(gè)配置的節(jié)點(diǎn):
如果我們?cè)谂渲梦募渲昧松鲜龅男畔ⅲ敲次覀兙涂梢杂肁uthenticate方法來(lái)檢查提供了用戶信息(用戶名和密碼)是否正確,如果我們沒(méi)有在web.config配置用戶的信息,也就是說(shuō)我們是把信息保存在數(shù)據(jù)庫(kù)等其他的地方,那么我們就不能Authenticate這個(gè)方法。當(dāng)然我們很少用Authenticate這個(gè)方法,因?yàn)槲覀儾豢赡馨阉杏脩粜畔⒂簿幋a到配置文件中,但是還是要清楚這個(gè)方法。
另外我簡(jiǎn)單的介紹一些常用的方法,具體的使用我以后會(huì)講述。
在FormsAuthenticate中使用頻繁的是RedirectFromLoginPage方法。每當(dāng)驗(yàn)證了用戶的憑證后就會(huì)使用到這個(gè)方法,也就是我們之前說(shuō)過(guò)的:跳轉(zhuǎn)到我們最初請(qǐng)求的頁(yè)面。
這個(gè)方法就這么簡(jiǎn)單的一"跳",但是其實(shí)在內(nèi)部做了很多的事情:
1.為用戶創(chuàng)建一個(gè)身份驗(yàn)證的票據(jù)
2.對(duì)身份驗(yàn)證的票據(jù)進(jìn)行加密
3.創(chuàng)建一個(gè)cookie,把加密的票據(jù)保存在cookie中
4.向HTTP響應(yīng)添加cookie,并且發(fā)送給客戶端。
5.跳轉(zhuǎn),并且把用戶重定向到最初請(qǐng)求的頁(yè)面
另外FormsAuthenticate類還有很多的其他方法和屬性:
FormsAuthenticate中涉及到客戶端保存cookie的兩個(gè)屬性就是:
FormsCookieName:獲取或者設(shè)設(shè)置cookie的名稱
FormsCookiePath:獲取或者設(shè)置cookie的url路徑
其中FormsCookiePath屬性有一點(diǎn)要注意:大多數(shù)的瀏覽器會(huì)在判斷cookie是否要和請(qǐng)求一起發(fā)送時(shí),用到cookie路徑。(我們一般在配置文件配置path="/"),如果我們配置的path不是"/",那么這個(gè)cookie就不會(huì)和請(qǐng)求發(fā)送到服務(wù)器端.
FormsAuthenticate中和cookie操作相關(guān)的方法有:
Decrypt:提取身份驗(yàn)證cookie的加密信息,創(chuàng)建FormsAuthenticationTicket,也就是解密。
Encrypt:加密。從FormsAuthenticationTicket中獲取信息,并且加密。以備我們之后把加密的信息寫入cookie
GetAuthCookie:創(chuàng)建身份驗(yàn)證cookie,但是并不把它立即添加到HTTP響應(yīng)中
SetAuthCookie:創(chuàng)建身份驗(yàn)證cookie,并且把它添加到Response.Cookie中。
RenewTicketIfOld:刷新身份驗(yàn)證cookie的生命周期
GetRedirectUrl:把用戶重定向到他們最初請(qǐng)求的頁(yè)面。
SignOut:使得當(dāng)前的身份驗(yàn)證cookie過(guò)期。我們常用的注銷功能。
FormsIdentity
大家現(xiàn)在應(yīng)該知道什么是標(biāo)識(shí) Identity,它包含了用戶名和ID標(biāo)識(shí)信息,可以參看我前面的文章。
FormsAuthenticationTicket 票據(jù)
通過(guò)上面的講解,大家已經(jīng)對(duì)它不陌生了,F(xiàn)ormsAuthenticationTicket實(shí)際上就包含用戶信息的一個(gè)類的實(shí)例。
注意:FormsAuthenticationTicket和cookie之間的區(qū)別:
cookie其實(shí)就是一個(gè)載體,容器,它包含了加密后的FormsAuthenticationTicket。
FormsAuthenticationTicket類的UserName屬性就是用戶的用戶名,我們可以根據(jù)這個(gè)屬性識(shí)別不同的用戶。
由于身份驗(yàn)證是基于cookie的,所以要考慮到cookie的過(guò)期的問(wèn)題。比如我們?cè)诘卿洉r(shí)有個(gè)"記住我"的checkbox,如果勾上,那么就創(chuàng)建了一個(gè)永不過(guò)期的cookie,處于安全,我不提倡這樣。
所以在FormsAuthenticationTicket也提供了關(guān)于設(shè)置cookie屬性:
Expiration:獲取一個(gè)表示cookie期滿的DateTime對(duì)象
Expired:判斷cookie是否過(guò)期
IsPersistent:是否在用戶關(guān)閉瀏覽器后繼續(xù)保存cookie
IssueDate:返回最初設(shè)置cookie的時(shí)間
還有就是CookiePath:設(shè)置cookie的保存路徑,前面談?wù)撨^(guò)了,一般設(shè)置為"/"。
另外FormsAuthenticationTicket身份驗(yàn)證票據(jù)目的是識(shí)別用戶。同時(shí),我們也可以利用FormsAuthenticationTicket的UserData屬性添加額外的信息,如角色等,然后這額外的信息就可以保存在cookie中。
今天就談這里。大家先有個(gè)總體的認(rèn)識(shí),具體的代碼部分,我們后面談。謝謝各位!!!
NET技術(shù):ASP.NET安全問(wèn)題--Forms驗(yàn)證的具體介紹(上篇),轉(zhuǎn)載需保留來(lái)源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。