国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Cookie/Session機(jī)制詳解

番茄西紅柿 / 1222人閱讀

摘要:要跟蹤該會(huì)話,必須引入一種機(jī)制。服務(wù)器檢查該,以此來(lái)辨認(rèn)用戶狀態(tài)。提示中保存中文只能編碼。不推薦使用等中文編碼,因?yàn)闉g覽器不一定支持,而且也不支持編碼。這是由的隱私安全機(jī)制決定的。隱私安全機(jī)制能夠禁止網(wǎng)站非法獲取其他網(wǎng)站的。

會(huì)話(Session)跟蹤是Web程序中常用的技術(shù),用來(lái)跟蹤用戶的整個(gè)會(huì)話。常用的會(huì)話跟蹤技術(shù)是Cookie與Session。Cookie通過(guò)在客戶端記錄信息確定用戶身份,Session通過(guò)在服務(wù)器端記錄信息確定用戶身份。

本章將系統(tǒng)地講述Cookie與Session機(jī)制,并比較說(shuō)明什么時(shí)候不能用Cookie,什么時(shí)候不能用Session。

 

1.1  Cookie機(jī)制

在程序中,會(huì)話跟蹤是很重要的事情。理論上,一個(gè)用戶的所有請(qǐng)求操作都應(yīng)該屬于同一個(gè)會(huì)話,而另一個(gè)用戶的所有請(qǐng)求操作則應(yīng)該屬于另一個(gè)會(huì)話,二者不能混淆。例如,用戶A在超市購(gòu)買的任何商品都應(yīng)該放在A的購(gòu)物車內(nèi),不論是用戶A什么時(shí)間購(gòu)買的,這都是屬于同一個(gè)會(huì)話的,不能放入用戶B或用戶C的購(gòu)物車內(nèi),這不屬于同一個(gè)會(huì)話。

而Web應(yīng)用程序是使用HTTP協(xié)議傳輸數(shù)據(jù)的。HTTP協(xié)議是無(wú)狀態(tài)的協(xié)議。一旦數(shù)據(jù)交換完畢,客戶端與服務(wù)器端的連接就會(huì)關(guān)閉,再次交換數(shù)據(jù)需要建立新的連接。這就意味著服務(wù)器無(wú)法從連接上跟蹤會(huì)話。即用戶A購(gòu)買了一件商品放入購(gòu)物車內(nèi),當(dāng)再次購(gòu)買商品時(shí)服務(wù)器已經(jīng)無(wú)法判斷該購(gòu)買行為是屬于用戶A的會(huì)話還是用戶B的會(huì)話了。要跟蹤該會(huì)話,必須引入一種機(jī)制。

Cookie就是這樣的一種機(jī)制。它可以彌補(bǔ)HTTP協(xié)議無(wú)狀態(tài)的不足。在Session出現(xiàn)之前,基本上所有的網(wǎng)站都采用Cookie來(lái)跟蹤會(huì)話。

1.1.1  什么是Cookie

Cookie意為“甜餅”,是由W3C組織提出,最早由Netscape社區(qū)發(fā)展的一種機(jī)制。目前Cookie已經(jīng)成為標(biāo)準(zhǔn),所有的主流瀏覽器如IE、Netscape、Firefox、Opera等都支持Cookie。

由于HTTP是一種無(wú)狀態(tài)的協(xié)議,服務(wù)器單從網(wǎng)絡(luò)連接上無(wú)從知道客戶身份。怎么辦呢?就給客戶端們頒發(fā)一個(gè)通行證吧,每人一個(gè),無(wú)論誰(shuí)訪問(wèn)都必須攜帶自己通行證。這樣服務(wù)器就能從通行證上確認(rèn)客戶身份了。這就是Cookie的工作原理。

Cookie實(shí)際上是一小段的文本信息。客戶端請(qǐng)求服務(wù)器,如果服務(wù)器需要記錄該用戶狀態(tài),就使用response向客戶端瀏覽器頒發(fā)一個(gè)Cookie??蛻舳藶g覽器會(huì)把Cookie保存起來(lái)。當(dāng)瀏覽器再請(qǐng)求該網(wǎng)站時(shí),瀏覽器把請(qǐng)求的網(wǎng)址連同該Cookie一同提交給服務(wù)器。服務(wù)器檢查該Cookie,以此來(lái)辨認(rèn)用戶狀態(tài)。服務(wù)器還可以根據(jù)需要修改Cookie的內(nèi)容。

 

 

查看某個(gè)網(wǎng)站頒發(fā)的Cookie很簡(jiǎn)單。在瀏覽器地址欄輸入javascript:alert (document. cookie)就可以了(需要有網(wǎng)才能查看)。JavaScript腳本會(huì)彈出一個(gè)對(duì)話框顯示本網(wǎng)站頒發(fā)的所有Cookie的內(nèi)容,如圖1.1所示。

圖1.1  Baidu網(wǎng)站頒發(fā)的Cookie

 

圖1.1中彈出的對(duì)話框中顯示的為Baidu網(wǎng)站的Cookie。其中第一行BAIDUID記錄的就是筆者的身份helloweenvsfei,只是Baidu使用特殊的方法將Cookie信息加密了。

 

注意:Cookie功能需要瀏覽器的支持。

如果瀏覽器不支持Cookie(如大部分手機(jī)中的瀏覽器)或者把Cookie禁用了,Cookie功能就會(huì)失效。

不同的瀏覽器采用不同的方式保存Cookie。

IE瀏覽器會(huì)在“C:Documents and Settings你的用戶名Cookies”文件夾下以文本文件形式保存,一個(gè)文本文件保存一個(gè)Cookie。

 

1.1.2  記錄用戶訪問(wèn)次數(shù)

Java中把Cookie封裝成了javax.servlet.http.Cookie類。每個(gè)Cookie都是該Cookie類的對(duì)象。服務(wù)器通過(guò)操作Cookie類對(duì)象對(duì)客戶端Cookie進(jìn)行操作。通過(guò)request.getCookie()獲取客戶端提交的所有Cookie(以Cookie[]數(shù)組形式返回),通過(guò)response.addCookie(Cookiecookie)向客戶端設(shè)置Cookie。

Cookie對(duì)象使用key-value屬性對(duì)的形式保存用戶狀態(tài),一個(gè)Cookie對(duì)象保存一個(gè)屬性對(duì),一個(gè)request或者response同時(shí)使用多個(gè)Cookie。因?yàn)镃ookie類位于包javax.servlet.http.*下面,所以JSP中不需要import該類。

 

1.1.3  Cookie的不可跨域名性

很多網(wǎng)站都會(huì)使用Cookie。例如,Google會(huì)向客戶端頒發(fā)Cookie,Baidu也會(huì)向客戶端頒發(fā)Cookie。那瀏覽器訪問(wèn)Google會(huì)不會(huì)也攜帶上Baidu頒發(fā)的Cookie呢?或者Google能不能修改Baidu頒發(fā)的Cookie呢?

答案是否定的。Cookie具有不可跨域名性。根據(jù)Cookie規(guī)范,瀏覽器訪問(wèn)Google只會(huì)攜帶Google的Cookie,而不會(huì)攜帶Baidu的Cookie。Google也只能操作Google的Cookie,而不能操作Baidu的Cookie。

Cookie在客戶端是由瀏覽器來(lái)管理的。瀏覽器能夠保證Google只會(huì)操作Google的Cookie而不會(huì)操作Baidu的Cookie,從而保證用戶的隱私安全。瀏覽器判斷一個(gè)網(wǎng)站是否能操作另一個(gè)網(wǎng)站Cookie的依據(jù)是域名。Google與Baidu的域名不一樣,因此Google不能操作Baidu的Cookie。

需要注意的是,雖然網(wǎng)站images.google.com與網(wǎng)站www.google.com同屬于Google,但是域名不一樣,二者同樣不能互相操作彼此的Cookie。

 

注意:用戶登錄網(wǎng)站www.google.com之后會(huì)發(fā)現(xiàn)訪問(wèn)images.google.com時(shí)登錄信息仍然有效,而普通的Cookie是做不到的。這是因?yàn)镚oogle做了特殊處理。本章后面也會(huì)對(duì)Cookie做類似的處理。

 

1.1.4  Unicode編碼:保存中文

中文與英文字符不同,中文屬于Unicode字符,在內(nèi)存中占4個(gè)字符,而英文屬于ASCII字符,內(nèi)存中只占2個(gè)字節(jié)。Cookie中使用Unicode字符時(shí)需要對(duì)Unicode字符進(jìn)行編碼,否則會(huì)亂碼。

 

提示:Cookie中保存中文只能編碼。一般使用UTF-8編碼即可。不推薦使用GBK等中文編碼,因?yàn)闉g覽器不一定支持,而且JavaScript也不支持GBK編碼。

 

1.1.5  BASE64編碼:保存二進(jìn)制圖片

Cookie不僅可以使用ASCII字符與Unicode字符,還可以使用二進(jìn)制數(shù)據(jù)。例如在Cookie中使用數(shù)字證書,提供安全度。使用二進(jìn)制數(shù)據(jù)時(shí)也需要進(jìn)行編碼。

%注意:本程序僅用于展示Cookie中可以存儲(chǔ)二進(jìn)制內(nèi)容,并不實(shí)用。由于瀏覽器每次請(qǐng)求服務(wù)器都會(huì)攜帶Cookie,因此Cookie內(nèi)容不宜過(guò)多,否則影響速度。Cookie的內(nèi)容應(yīng)該少而精。

 

1.1.6  設(shè)置Cookie的所有屬性

除了name與value之外,Cookie還具有其他幾個(gè)常用的屬性。每個(gè)屬性對(duì)應(yīng)一個(gè)getter方法與一個(gè)setter方法。Cookie類的所有屬性如表1.1所示。

表1.1  Cookie常用屬性

屬  性  名

描    述

String name

該Cookie的名稱。Cookie一旦創(chuàng)建,名稱便不可更改

Object value

該Cookie的值。如果值為Unicode字符,需要為字符編碼。如果值為二進(jìn)制數(shù)據(jù),則需要使用BASE64編碼

int maxAge

該Cookie失效的時(shí)間,單位秒。如果為正數(shù),則該Cookie在maxAge秒之后失效。如果為負(fù)數(shù),該Cookie為臨時(shí)Cookie,關(guān)閉瀏覽器即失效,瀏覽器也不會(huì)以任何形式保存該Cookie。如果為0,表示刪除該Cookie。默認(rèn)為–1

boolean secure

該Cookie是否僅被使用安全協(xié)議傳輸。安全協(xié)議。安全協(xié)議有HTTPS,SSL等,在網(wǎng)絡(luò)上傳輸數(shù)據(jù)之前先將數(shù)據(jù)加密。默認(rèn)為false

String path

該Cookie的使用路徑。如果設(shè)置為“/sessionWeb/”,則只有contextPath為“/sessionWeb”的程序可以訪問(wèn)該Cookie。如果設(shè)置為“/”,則本域名下contextPath都可以訪問(wèn)該Cookie。注意最后一個(gè)字符必須為“/”

String domain

可以訪問(wèn)該Cookie的域名。如果設(shè)置為“.google.com”,則所有以“google.com”結(jié)尾的域名都可以訪問(wèn)該Cookie。注意第一個(gè)字符必須為“.”

String comment

該Cookie的用處說(shuō)明。瀏覽器顯示Cookie信息的時(shí)候顯示該說(shuō)明

int version

該Cookie使用的版本號(hào)。0表示遵循Netscape的Cookie規(guī)范,1表示遵循W3C的RFC 2109規(guī)范

 

1.1.7  Cookie的有效期

Cookie的maxAge決定著Cookie的有效期,單位為秒(Second)。Cookie中通過(guò)getMaxAge()方法與setMaxAge(int maxAge)方法來(lái)讀寫maxAge屬性。

如果maxAge屬性為正數(shù),則表示該Cookie會(huì)在maxAge秒之后自動(dòng)失效。瀏覽器會(huì)將maxAge為正數(shù)的Cookie持久化,即寫到對(duì)應(yīng)的Cookie文件中。無(wú)論客戶關(guān)閉了瀏覽器還是電腦,只要還在maxAge秒之前,登錄網(wǎng)站時(shí)該Cookie仍然有效。下面代碼中的Cookie信息將永遠(yuǎn)有效。

 

Cookie cookie = new Cookie("username","helloweenvsfei");   // 新建Cookie

cookie.setMaxAge(Integer.MAX_VALUE);           // 設(shè)置生命周期為MAX_VALUE

response.addCookie(cookie);                    // 輸出到客戶端

 

如果maxAge為負(fù)數(shù),則表示該Cookie僅在本瀏覽器窗口以及本窗口打開(kāi)的子窗口內(nèi)有效,關(guān)閉窗口后該Cookie即失效。maxAge為負(fù)數(shù)的Cookie,為臨時(shí)性Cookie,不會(huì)被持久化,不會(huì)被寫到Cookie文件中。Cookie信息保存在瀏覽器內(nèi)存中,因此關(guān)閉瀏覽器該Cookie就消失了。Cookie默認(rèn)的maxAge值為–1。

如果maxAge為0,則表示刪除該Cookie。Cookie機(jī)制沒(méi)有提供刪除Cookie的方法,因此通過(guò)設(shè)置該Cookie即時(shí)失效實(shí)現(xiàn)刪除Cookie的效果。失效的Cookie會(huì)被瀏覽器從Cookie文件或者內(nèi)存中刪除,

 

例如:

Cookie cookie = new Cookie("username","helloweenvsfei");   // 新建Cookie

cookie.setMaxAge(0);                          // 設(shè)置生命周期為0,不能為負(fù)數(shù)

response.addCookie(cookie);                    // 必須執(zhí)行這一句

 

response對(duì)象提供的Cookie操作方法只有一個(gè)添加操作add(Cookie cookie)。

要想修改Cookie只能使用一個(gè)同名的Cookie來(lái)覆蓋原來(lái)的Cookie,達(dá)到修改的目的。刪除時(shí)只需要把maxAge修改為0即可。

 

注意:從客戶端讀取Cookie時(shí),包括maxAge在內(nèi)的其他屬性都是不可讀的,也不會(huì)被提交。瀏覽器提交Cookie時(shí)只會(huì)提交name與value屬性。maxAge屬性只被瀏覽器用來(lái)判斷Cookie是否過(guò)期。

 

1.1.8  Cookie的修改、刪除

Cookie并不提供修改、刪除操作。如果要修改某個(gè)Cookie,只需要新建一個(gè)同名的Cookie,添加到response中覆蓋原來(lái)的Cookie。

如果要?jiǎng)h除某個(gè)Cookie,只需要新建一個(gè)同名的Cookie,并將maxAge設(shè)置為0,并添加到response中覆蓋原來(lái)的Cookie。注意是0而不是負(fù)數(shù)。負(fù)數(shù)代表其他的意義。讀者可以通過(guò)上例的程序進(jìn)行驗(yàn)證,設(shè)置不同的屬性。

 

注意:修改、刪除Cookie時(shí),新建的Cookie除value、maxAge之外的所有屬性,例如name、path、domain等,都要與原Cookie完全一樣。否則,瀏覽器將視為兩個(gè)不同的Cookie不予覆蓋,導(dǎo)致修改、刪除失敗。

 

1.1.9  Cookie的域名

Cookie是不可跨域名的。域名www.google.com頒發(fā)的Cookie不會(huì)被提交到域名www.baidu.com去。這是由Cookie的隱私安全機(jī)制決定的。隱私安全機(jī)制能夠禁止網(wǎng)站非法獲取其他網(wǎng)站的Cookie。

正常情況下,同一個(gè)一級(jí)域名下的兩個(gè)二級(jí)域名如www.helloweenvsfei.com和images.helloweenvsfei.com也不能交互使用Cookie,因?yàn)槎叩挠蛎⒉粐?yán)格相同。如果想所有helloweenvsfei.com名下的二級(jí)域名都可以使用該Cookie,需要設(shè)置Cookie的domain參數(shù),例如:

Cookie cookie = new Cookie("time","20080808"); // 新建Cookie

cookie.setDomain(".helloweenvsfei.com");           // 設(shè)置域名

cookie.setPath("/");                              // 設(shè)置路徑

cookie.setMaxAge(Integer.MAX_VALUE);               // 設(shè)置有效期

response.addCookie(cookie);                       // 輸出到客戶端

 

讀者可以修改本機(jī)C:WINDOWSsystem32driversetc下的hosts文件來(lái)配置多個(gè)臨時(shí)域名,然后使用setCookie.jsp程序來(lái)設(shè)置跨域名Cookie驗(yàn)證domain屬性。

注意:domain參數(shù)必須以點(diǎn)(".")開(kāi)始。另外,name相同但domain不同的兩個(gè)Cookie是兩個(gè)不同的Cookie。如果想要兩個(gè)域名完全不同的網(wǎng)站共有Cookie,可以生成兩個(gè)Cookie,domain屬性分別為兩個(gè)域名,輸出到客戶端。

 

1.1.10  Cookie的路徑

domain屬性決定運(yùn)行訪問(wèn)Cookie的域名,而path屬性決定允許訪問(wèn)Cookie的路徑(ContextPath)。例如,如果只允許/sessionWeb/下的程序使用Cookie,可以這么寫:

Cookie cookie = new Cookie("time","20080808");     // 新建Cookie

cookie.setPath("/session/");                          // 設(shè)置路徑

response.addCookie(cookie);                           // 輸出到客戶端

設(shè)置為“/”時(shí)允許所有路徑使用Cookie。path屬性需要使用符號(hào)“/”結(jié)尾。name相同但domain相同的兩個(gè)Cookie也是兩個(gè)不同的Cookie。

 

注意:頁(yè)面只能獲取它屬于的Path的Cookie。例如/session/test/a.jsp不能獲取到路徑為/session/abc/的Cookie。使用時(shí)一定要注意。

 

1.1.11  Cookie的安全屬性

HTTP協(xié)議不僅是無(wú)狀態(tài)的,而且是不安全的。使用HTTP協(xié)議的數(shù)據(jù)不經(jīng)過(guò)任何加密就直接在網(wǎng)絡(luò)上傳播,有被截獲的可能。使用HTTP協(xié)議傳輸很機(jī)密的內(nèi)容是一種隱患。如果不希望Cookie在HTTP等非安全協(xié)議中傳輸,可以設(shè)置Cookie的secure屬性為true。瀏覽器只會(huì)在HTTPS和SSL等安全協(xié)議中傳輸此類Cookie。下面的代碼設(shè)置secure屬性為true:

 

Cookie cookie = new Cookie("time", "20080808"); // 新建Cookie

cookie.setSecure(true);                           // 設(shè)置安全屬性

response.addCookie(cookie);                        // 輸出到客戶端

 

提示:secure屬性并不能對(duì)Cookie內(nèi)容加密,因而不能保證絕對(duì)的安全性。如果需要高安全性,需要在程序中對(duì)Cookie內(nèi)容加密、解密,以防泄密。

 

1.1.12  JavaScript操作Cookie

Cookie是保存在瀏覽器端的,因此瀏覽器具有操作Cookie的先決條件。瀏覽器可以使用腳本程序如JavaScript或者VBScript等操作Cookie。這里以JavaScript為例介紹常用的Cookie操作。例如下面的代碼會(huì)輸出本頁(yè)面所有的Cookie。

由于JavaScript能夠任意地讀寫Cookie,有些好事者便想使用JavaScript程序去窺探用戶在其他網(wǎng)站的Cookie。不過(guò)這是徒勞的,W3C組織早就意識(shí)到JavaScript對(duì)Cookie的讀寫所帶來(lái)的安全隱患并加以防備了,W3C標(biāo)準(zhǔn)的瀏覽器會(huì)阻止JavaScript讀寫任何不屬于自己網(wǎng)站的Cookie。換句話說(shuō),A網(wǎng)站的JavaScript程序讀寫B(tài)網(wǎng)站的Cookie不會(huì)有任何結(jié)果。

 

1.1.13  案例:永久登錄

如果用戶是在自己家的電腦上上網(wǎng),登錄時(shí)就可以記住他的登錄信息,下次訪問(wèn)時(shí)不需要再次登錄,直接訪問(wèn)即可。實(shí)現(xiàn)方法是把登錄信息如賬號(hào)、密碼等保存在Cookie中,并控制Cookie的有效期,下次訪問(wèn)時(shí)再驗(yàn)證Cookie中的登錄信息即可。

保存登錄信息有多種方案。最直接的是把用戶名與密碼都保持到Cookie中,下次訪問(wèn)時(shí)檢查Cookie中的用戶名與密碼,與數(shù)據(jù)庫(kù)比較。這是一種比較危險(xiǎn)的選擇,一般不把密碼等重要信息保存到Cookie中。

還有一種方案是把密碼加密后保存到Cookie中,下次訪問(wèn)時(shí)解密并與數(shù)據(jù)庫(kù)比較。這種方案略微安全一些。如果不希望保存密碼,還可以把登錄的時(shí)間戳保存到Cookie與數(shù)據(jù)庫(kù)中,到時(shí)只驗(yàn)證用戶名與登錄時(shí)間戳就可以了。

這幾種方案驗(yàn)證賬號(hào)時(shí)都要查詢數(shù)據(jù)庫(kù)。

本例將采用另一種方案,只在登錄時(shí)查詢一次數(shù)據(jù)庫(kù),以后訪問(wèn)驗(yàn)證登錄信息時(shí)不再查詢數(shù)據(jù)庫(kù)。實(shí)現(xiàn)方式是把賬號(hào)按照一定的規(guī)則加密后,連同賬號(hào)一塊保存到Cookie中。下次訪問(wèn)時(shí)只需要判斷賬號(hào)的加密規(guī)則是否正確即可。本例把賬號(hào)保存到名為account的Cookie中,把賬號(hào)連同密鑰用MD1算法加密后保存到名為ssid的Cookie中。驗(yàn)證時(shí)驗(yàn)證Cookie中的賬號(hào)與密鑰加密后是否與Cookie中的ssid相等。相關(guān)代碼如下:

代碼1.8 loginCookie.jsp

<%@ page language="java"pageEncoding="UTF-8" isErrorPage="false" %>

<%!                                                  // JSP方法

    private static final String KEY =":cookie@helloweenvsfei.com";
                                                     // 密鑰 

    public final static String calcMD1(Stringss) { // MD1 加密算法

       String s = ss==null ?"" : ss;                  // 若為null返回空

       char hexDigits[] = { 0,1, 2, 3, 4, 1, 6, 7, 8, 9,
       a, b, c, d, e, f };                        // 字典

       try {

        byte[] strTemp =s.getBytes();                          // 獲取字節(jié)

        MessageDigestmdTemp = MessageDigest.getInstance("MD1"); // 獲取MD1

       mdTemp.update(strTemp);                                // 更新數(shù)據(jù)

        byte[] md =mdTemp.digest();                        // 加密

        int j =md.length;                                 // 加密后的長(zhǎng)度

        char str[] = newchar[j * 2];                       // 新字符串?dāng)?shù)組

        int k =0;                                         // 計(jì)數(shù)器k

        for (int i = 0; i< j; i++) {                       // 循環(huán)輸出

         byte byte0 =md[i];

         str[k++] =hexDigits[byte0 >>> 4 & 0xf];

         str[k++] =hexDigits[byte0 & 0xf];

        }

        return newString(str);                             // 加密后字符串

       } catch (Exception e){return null; }

    }

%>

<%

   request.setCharacterEncoding("UTF-8");             // 設(shè)置request編碼

    response.setCharacterEncoding("UTF-8");        // 設(shè)置response編碼

    

    String action =request.getParameter("action"); // 獲取action參數(shù)

    

    if("login".equals(action)){                       // 如果為login動(dòng)作

        String account =request.getParameter("account");
                                                     // 獲取account參數(shù)

        String password =request.getParameter("password");
                                                     // 獲取password參數(shù)

        int timeout = newInteger(request.getParameter("timeout"));
                                                     // 獲取timeout參數(shù)

               

        String ssid =calcMD1(account + KEY); // 把賬號(hào)、密鑰使用MD1加密后保存

        

        CookieaccountCookie = new Cookie("account", account);
                                                     // 新建Cookie

       accountCookie.setMaxAge(timeout);              // 設(shè)置有效期

        

        Cookie ssidCookie =new Cookie("ssid", ssid);   // 新建Cookie

       ssidCookie.setMaxAge(timeout);                 // 設(shè)置有效期

        

       response.addCookie(accountCookie);             // 輸出到客戶端

       response.addCookie(ssidCookie);            // 輸出到客戶端

        

        // 重新請(qǐng)求本頁(yè)面,參數(shù)中帶有時(shí)間戳,禁止瀏覽器緩存頁(yè)面內(nèi)容

       response.sendRedirect(request.getRequestURI() + "?" + System.
        currentTimeMillis());

        return;

    }

    elseif("logout".equals(action)){                  // 如果為logout動(dòng)作

        

        CookieaccountCookie = new Cookie("account", "");
                                                 // 新建Cookie,內(nèi)容為空

       accountCookie.setMaxAge(0);                // 設(shè)置有效期為0,刪除

               

        Cookie ssidCookie =new Cookie("ssid", ""); // 新建Cookie,內(nèi)容為空

       ssidCookie.setMaxAge(0);                   // 設(shè)置有效期為0,刪除

       response.addCookie(accountCookie);         // 輸出到客戶端

       response.addCookie(ssidCookie);         // 輸出到客戶端

        //重新請(qǐng)求本頁(yè)面,參數(shù)中帶有時(shí)間戳,禁止瀏覽器緩存頁(yè)面內(nèi)容

       response.sendRedirect(request.getRequestURI() + "?" + System.
        currentTimeMillis());

        return;

    }

    boolean login = false;                        // 是否登錄

    String account = null;                        // 賬號(hào)

    String ssid = null;                           // SSID標(biāo)識(shí)

    

    if(request.getCookies() !=null){               // 如果Cookie不為空

        for(Cookie cookie :request.getCookies()){  // 遍歷Cookie

           if(cookie.getName().equals("account"))  // 如果Cookie名為
                                                    account

               account = cookie.getValue();       // 保存account內(nèi)容

           if(cookie.getName().equals("ssid")) // 如果為SSID

               ssid = cookie.getValue();          // 保存SSID內(nèi)容

        }

    }

    if(account != null && ssid !=null){    // 如果account、SSID都不為空

        login =ssid.equals(calcMD1(account + KEY));
                                      // 如果加密規(guī)則正確, 則視為已經(jīng)登錄

    }

%>

       <%= login ? "歡迎您回來(lái)" : "請(qǐng)先登錄"%>

        <% if(login){%>

            歡迎您, ${ cookie.account.value }.    

           
            注銷

        <% } else {%>

                method="post">

           

              

                  

              

              

                  

              

              

                  

                  

              

                  

              

           

賬號(hào):
密碼:
有效期:                    checked> 關(guān)閉瀏覽器即失效
                   name="timeout" value="<%= 30 *24 * 60 * 60 %>"> 30天
                   內(nèi)有效
                   "<%= Integer.MAX_VALUE %>"> 永久有效
                   "button">

       

        <% } %>

登錄時(shí)可以選擇登錄信息的有效期:關(guān)閉瀏覽器即失效、30天內(nèi)有效與永久有效。通過(guò)設(shè)置Cookie的age屬性來(lái)實(shí)現(xiàn),注意觀察代碼。運(yùn)行效果如圖1.7所示。

圖1.7  永久登錄

提示:該加密機(jī)制中最重要的部分為算法與密鑰。由于MD1算法的不可逆性,即使用戶知道了賬號(hào)與加密后的字符串,也不可能解密得到密鑰。因此,只要保管好密鑰與算法,該機(jī)制就是安全的。

 

1.2  Session機(jī)制

除了使用Cookie,Web應(yīng)用程序中還經(jīng)常使用Session來(lái)記錄客戶端狀態(tài)。Session是服務(wù)器端使用的一種記錄客戶端狀態(tài)的機(jī)制,使用上比Cookie簡(jiǎn)單一些,相應(yīng)的也增加了服務(wù)器的存儲(chǔ)壓力。

1.2.1  什么是Session

Session是另一種記錄客戶狀態(tài)的機(jī)制,不同的是Cookie保存在客戶端瀏覽器中,而Session保存在服務(wù)器上。客戶端瀏覽器訪問(wèn)服務(wù)器的時(shí)候,服務(wù)器把客戶端信息以某種形式記錄在服務(wù)器上。這就是Session??蛻舳藶g覽器再次訪問(wèn)時(shí)只需要從該Session中查找該客戶的狀態(tài)就可以了。

如果說(shuō)Cookie機(jī)制是通過(guò)檢查客戶身上的“通行證”來(lái)確定客戶身份的話,那么Session機(jī)制就是通過(guò)檢查服務(wù)器上的“客戶明細(xì)表”來(lái)確認(rèn)客戶身份。Session相當(dāng)于程序在服務(wù)器上建立的一份客戶檔案,客戶來(lái)訪的時(shí)候只需要查詢客戶檔案表就可以了。

1.2.2  實(shí)現(xiàn)用戶登錄

Session對(duì)應(yīng)的類為javax.servlet.http.HttpSession類。每個(gè)來(lái)訪者對(duì)應(yīng)一個(gè)Session對(duì)象,所有該客戶的狀態(tài)信息都保存在這個(gè)Session對(duì)象里。Session對(duì)象是在客戶端第一次請(qǐng)求服務(wù)器的時(shí)候創(chuàng)建的。Session也是一種key-value的屬性對(duì),通過(guò)getAttribute(Stringkey)和setAttribute(String key,Objectvalue)方法讀寫客戶狀態(tài)信息。Servlet里通過(guò)request.getSession()方法獲取該客戶的Session,

例如:

HttpSession session = request.getSession();       // 獲取Session對(duì)象

session.setAttribute("loginTime", new Date());     // 設(shè)置Session中的屬性

    

out.println("登錄時(shí)間為:" +(Date)session.getAttribute("loginTime"));      // 獲取Session屬性

request還可以使用getSession(boolean create)來(lái)獲取Session。區(qū)別是如果該客戶的Session不存在,request.getSession()方法會(huì)返回null,而getSession(true)會(huì)先創(chuàng)建Session再將Session返回。

Servlet中必須使用request來(lái)編程式獲取HttpSession對(duì)象,而JSP中內(nèi)置了Session隱藏對(duì)象,可以直接使用。如果使用聲明了<%@page session="false" %>,則Session隱藏對(duì)象不可用。下面的例子使用Session記錄客戶賬號(hào)信息。

源代碼如下:

代碼1.9  session.jsp

<%@ page language="java" pageEncoding="UTF-8"%>

<%!

    DateFormat dateFormat = newSimpleDateFormat("yyyy-MM-dd");         // 日期格式化器

%>

<%

    response.setCharacterEncoding("UTF-8");        // 設(shè)置request編碼

    Person[] persons =

    {           

       // 基礎(chǔ)數(shù)據(jù),保存三個(gè)人的信息

        new Person("Liu Jinghua","password1", 34, dateFormat.parse
        ("1982-01-01")),

        new Person("Hello Kitty","hellokitty", 23, dateFormat.parse
        ("1984-02-21")),

        new Person("Garfield", "garfield_pass",23, dateFormat.parse
        ("1994-09-12")),

     };

    

    String message = "";                      // 要顯示的消息

    

    if(request.getMethod().equals("POST"))

    { 

        // 如果是POST登錄        

        for(Person person :persons)

        {           

            // 遍歷基礎(chǔ)數(shù)據(jù),驗(yàn)證賬號(hào)、密碼

            // 如果用戶名正確且密碼正確

           if(person.getName().equalsIgnoreCase(request.getParameter("username"))&&person.getPassword().equals(request.getParameter("password")))

           {               

               // 登錄成功,設(shè)置將用戶的信息以及登錄時(shí)間保存到Session

               session.setAttribute("person", person);                   // 保存登錄的Person

               session.setAttribute("loginTime", new Date());          // 保存登錄的時(shí)間              

               response.sendRedirect(request.getContextPath() + "/welcome.jsp");

               return;

            }

        }       

        message = "用戶名密碼不匹配,登錄失敗。";       // 登錄失敗

    }

%>

    // ... HTML代碼為一個(gè)FORM表單,代碼略,請(qǐng)看隨書光盤

 

登錄界面驗(yàn)證用戶登錄信息,如果登錄正確,就把用戶信息以及登錄時(shí)間保存進(jìn)Session,然后轉(zhuǎn)到歡迎頁(yè)面welcome.jsp。welcome.jsp中從Session中獲取信息,并將用戶資料顯示出來(lái)。

welcome.jsp代碼如下:

代碼1.10  welcome.jsp

<%@ page language="java" pageEncoding="UTF-8"%>

<%!

    DateFormat dateFormat = newSimpleDateFormat("yyyy-MM-dd");         // 日期格式化器

%>

<%

    Person person =(Person)session.getAttribute("person");                       // 獲取登錄的person

    Date loginTime =(Date)session.getAttribute("loginTime");                     // 獲取登錄時(shí)間

%>

    // ... 部分HTML代碼略

           

              

                  

              

              

                  

              

              

                  

              

              

                  

              

           

您的姓名: <%= person.getName()%>
登錄時(shí)間: <%= loginTime%>
您的年齡: <%= person.getAge()%>
您的生日: <%=dateFormat.format(person.getBirthday()) %>

程序運(yùn)行效果如圖1.8所示。

圖1.8  使用Session記錄用戶信息

注意程序中Session中直接保存了Person類對(duì)象與Date類對(duì)象,使用起來(lái)要比Cookie方便。

當(dāng)多個(gè)客戶端執(zhí)行程序時(shí),服務(wù)器會(huì)保存多個(gè)客戶端的Session。獲取Session的時(shí)候也不需要聲明獲取誰(shuí)的Session。Session機(jī)制決定了當(dāng)前客戶只會(huì)獲取到自己的Session,而不會(huì)獲取到別人的Session。各客戶的Session也彼此獨(dú)立,互不可見(jiàn)。

 

提示:Session的使用比Cookie方便,但是過(guò)多的Session存儲(chǔ)在服務(wù)器內(nèi)存中,會(huì)對(duì)服務(wù)器造成壓力。

 

1.2.3  Session的生命周期

Session保存在服務(wù)器端。為了獲得更高的存取速度,服務(wù)器一般把Session放在內(nèi)存里。每個(gè)用戶都會(huì)有一個(gè)獨(dú)立的Session。如果Session內(nèi)容過(guò)于復(fù)雜,當(dāng)大量客戶訪問(wèn)服務(wù)器時(shí)可能會(huì)導(dǎo)致內(nèi)存溢出。因此,Session里的信息應(yīng)該盡量精簡(jiǎn)。

Session在用戶第一次訪問(wèn)服務(wù)器的時(shí)候自動(dòng)創(chuàng)建。需要注意只有訪問(wèn)JSP、Servlet等程序時(shí)才會(huì)創(chuàng)建Session,只訪問(wèn)HTML、IMAGE等靜態(tài)資源并不會(huì)創(chuàng)建Session。如果尚未生成Session,也可以使用request.getSession(true)強(qiáng)制生成Session。

Session生成后,只要用戶繼續(xù)訪問(wèn),服務(wù)器就會(huì)更新Session的最后訪問(wèn)時(shí)間,并維護(hù)該Session。用戶每訪問(wèn)服務(wù)器一次,無(wú)論是否讀寫Session,服務(wù)器都認(rèn)為該用戶的Session“活躍(active)”了一次。

 

1.2.4  Session的有效期

由于會(huì)有越來(lái)越多的用戶訪問(wèn)服務(wù)器,因此Session也會(huì)越來(lái)越多。為防止內(nèi)存溢出,服務(wù)器會(huì)把長(zhǎng)時(shí)間內(nèi)沒(méi)有活躍的Session從內(nèi)存刪除。這個(gè)時(shí)間就是Session的超時(shí)時(shí)間。如果超過(guò)了超時(shí)時(shí)間沒(méi)訪問(wèn)過(guò)服務(wù)器,Session就自動(dòng)失效了。

Session的超時(shí)時(shí)間為maxInactiveInterval屬性,可以通過(guò)對(duì)應(yīng)的getMaxInactiveInterval()獲取,通過(guò)setMaxInactiveInterval(longinterval)修改。

Session的超時(shí)時(shí)間也可以在web.xml中修改。另外,通過(guò)調(diào)用Session的invalidate()方法可以使Session失效。

 

1.2.5  Session的常用方法

Session中包括各種方法,使用起來(lái)要比Cookie方便得多。Session的常用方法如表1.2所示。

表1.2  HttpSession的常用方法

方  法  名

描    述

void setAttribute(String attribute, Object value)

設(shè)置Session屬性。value參數(shù)可以為任何Java Object。通常為Java Bean。value信息不宜過(guò)大

String getAttribute(String attribute)

返回Session屬性

Enumeration getAttributeNames()

返回Session中存在的屬性名

void removeAttribute(String attribute)

移除Session屬性

String getId()

返回Session的ID。該ID由服務(wù)器自動(dòng)創(chuàng)建,不會(huì)重復(fù)

long getCreationTime()

返回Session的創(chuàng)建日期。返回類型為long,常被轉(zhuǎn)化為Date類型,例如:Date createTime = new Date(session.get CreationTime())

long getLastAccessedTime()

返回Session的最后活躍時(shí)間。返回類型為long

int getMaxInactiveInterval()

返回Session的超時(shí)時(shí)間。單位為秒。超過(guò)該時(shí)間沒(méi)有訪問(wèn),服務(wù)器認(rèn)為該Session失效

void setMaxInactiveInterval(int second)

設(shè)置Session的超時(shí)時(shí)間。單位為秒

void putValue(String attribute, Object value)

不推薦的方法。已經(jīng)被setAttribute(String attribute, Object Value)替代

Object getValue(String attribute)

不被推薦的方法。已經(jīng)被getAttribute(String attr)替代

boolean isNew()

返回該Session是否是新創(chuàng)建的

void invalidate()

使該Session失效

Tomcat中Session的默認(rèn)超時(shí)時(shí)間為20分鐘。通過(guò)setMaxInactiveInterval(int seconds)修改超時(shí)時(shí)間??梢孕薷膚eb.xml改變Session的默認(rèn)超時(shí)時(shí)間。例如修改為60分鐘:

   60     

 

注意:參數(shù)的單位為分鐘,而setMaxInactiveInterval(int s)單位為秒。

 

1.2.6  Session對(duì)瀏覽器的要求

雖然Session保存在服務(wù)器,對(duì)客戶端是透明的,它的正常運(yùn)行仍然需要客戶端瀏覽器的支持。這是因?yàn)镾ession需要使用Cookie作為識(shí)別標(biāo)志。HTTP協(xié)議是無(wú)狀態(tài)的,Session不能依據(jù)HTTP連接來(lái)判斷是否為同一客戶,因此服務(wù)器向客戶端瀏覽器發(fā)送一個(gè)名為JSESSIONID的Cookie,它的值為該Session的id(也就是HttpSession.getId()的返回值)。Session依據(jù)該Cookie來(lái)識(shí)別是否為同一用戶。

該Cookie為服務(wù)器自動(dòng)生成的,它的maxAge屬性一般為–1,表示僅當(dāng)前瀏覽器內(nèi)有效,并且各瀏覽器窗口間不共享,關(guān)閉瀏覽器就會(huì)失效。

因此同一機(jī)器的兩個(gè)瀏覽器窗口訪問(wèn)服務(wù)器時(shí),會(huì)生成兩個(gè)不同的Session。但是由瀏覽器窗口內(nèi)的鏈接、腳本等打開(kāi)的新窗口(也就是說(shuō)不是雙擊桌面瀏覽器圖標(biāo)等打開(kāi)的窗口)除外。這類子窗口會(huì)共享父窗口的Cookie,因此會(huì)共享一個(gè)Session。

 

注意:新開(kāi)的瀏覽器窗口會(huì)生成新的Session,但子窗口除外。子窗口會(huì)共用父窗口的Session。例如,在鏈接上右擊,在彈出的快捷菜單中選擇“在新窗口中打開(kāi)”時(shí),子窗口便可以訪問(wèn)父窗口的Session。

如果客戶端瀏覽器將Cookie功能禁用,或者不支持Cookie怎么辦?例如,絕大多數(shù)的手機(jī)瀏覽器都不支持Cookie。Java Web提供了另一種解決方案:URL地址重寫。

 

1.2.7  URL地址重寫

URL地址重寫是對(duì)客戶端不支持Cookie的解決方案。URL地址重寫的原理是將該用戶Session的id信息重寫到URL地址中。服務(wù)器能夠解析重寫后的URL獲取Session的id。這樣即使客戶端不支持Cookie,也可以使用Session來(lái)記錄用戶狀態(tài)。HttpServletResponse類提供了encodeURL(Stringurl)實(shí)現(xiàn)URL地址重寫,例如:

    "> 
    Homepage

該方法會(huì)自動(dòng)判斷客戶端是否支持Cookie。如果客戶端支持Cookie,會(huì)將URL原封不動(dòng)地輸出來(lái)。如果客戶端不支持Cookie,則會(huì)將用戶Session的id重寫到URL中。重寫后的輸出可能是這樣的:

        1&wd=Java">Homepage

即在文件名的后面,在URL參數(shù)的前面添加了字符串“;jsessionid=XXX”。其中XXX為Session的id。分析一下可以知道,增添的jsessionid字符串既不會(huì)影響請(qǐng)求的文件名,也不會(huì)影響提交的地址欄參數(shù)。用戶單擊這個(gè)鏈接的時(shí)候會(huì)把Session的id通過(guò)URL提交到服務(wù)器上,服務(wù)器通過(guò)解析URL地址獲得Session的id。

如果是頁(yè)面重定向(Redirection),URL地址重寫可以這樣寫:

<%

    if(“administrator”.equals(userName))

    {

       response.sendRedirect(response.encodeRedirectURL(“administrator.jsp”));

        return;

    }

%>

效果跟response.encodeURL(String url)是一樣的:如果客戶端支持Cookie,生成原URL地址,如果不支持Cookie,傳回重寫后的帶有jsessionid字符串的地址。

對(duì)于WAP程序,由于大部分的手機(jī)瀏覽器都不支持Cookie,WAP程序都會(huì)采用URL地址重寫來(lái)跟蹤用戶會(huì)話。比如用友集團(tuán)的移動(dòng)商街等。

 

注意:TOMCAT判斷客戶端瀏覽器是否支持Cookie的依據(jù)是請(qǐng)求中是否含有Cookie。盡管客戶端可能會(huì)支持Cookie,但是由于第一次請(qǐng)求時(shí)不會(huì)攜帶任何Cookie(因?yàn)椴o(wú)任何Cookie可以攜帶),URL地址重寫后的地址中仍然會(huì)帶有jsessionid。當(dāng)?shù)诙卧L問(wèn)時(shí)服務(wù)器已經(jīng)在瀏覽器中寫入Cookie了,因此URL地址重寫后的地址中就不會(huì)帶有jsessionid了。

 

1.2.8  Session中禁止使用Cookie

既然WAP上大部分的客戶瀏覽器都不支持Cookie,索性禁止Session使用Cookie,統(tǒng)一使用URL地址重寫會(huì)更好一些。Java Web規(guī)范支持通過(guò)配置的方式禁用Cookie。下面舉例說(shuō)一下怎樣通過(guò)配置禁止使用Cookie。

打開(kāi)項(xiàng)目sessionWeb的WebRoot目錄下的META-INF文件夾(跟WEB-INF文件夾同級(jí),如果沒(méi)有則創(chuàng)建),打開(kāi)context.xml(如果沒(méi)有則創(chuàng)建),編輯內(nèi)容如下:

代碼1.11 /META-INF/context.xml

 

或者修改Tomcat全局的conf/context.xml,修改內(nèi)容如下:

代碼1.12  context.xml

   

部署后TOMCAT便不會(huì)自動(dòng)生成名JSESSIONID的Cookie,Session也不會(huì)以Cookie為識(shí)別標(biāo)志,而僅僅以重寫后的URL地址為識(shí)別標(biāo)志了。

 

注意:該配置只是禁止Session使用Cookie作為識(shí)別標(biāo)志,并不能阻止其他的Cookie讀寫。也就是說(shuō)服務(wù)器不會(huì)自動(dòng)維護(hù)名為JSESSIONID的Cookie了,但是程序中仍然可以讀寫其他的Cookie。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/2277.html

相關(guān)文章

  • cookiesession詳解

    摘要:所謂的無(wú)連接就是服務(wù)器收到了客戶端的請(qǐng)求之后,響應(yīng)完成并收到客戶端的應(yīng)答之后,即斷開(kāi)連接。從而節(jié)省傳輸時(shí)間。協(xié)議對(duì)事務(wù)的處理沒(méi)有記憶能力。這種方式某種方面上講解放了服務(wù)器,但是卻不利于客戶端與服務(wù)器的連接。 session與cookie是什么? session與cookie屬于一種會(huì)話控制技術(shù).常用在身份識(shí)別,登錄驗(yàn)證,數(shù)據(jù)傳輸?shù)?舉個(gè)例子,就像我們?nèi)コ匈I東西結(jié)賬的時(shí)候,我們要拿出我...

    SwordFly 評(píng)論0 收藏0
  • 詳解 CookieSession 關(guān)系和區(qū)別

    摘要:目前大多數(shù)的應(yīng)用都是用實(shí)現(xiàn)跟蹤的。的安全性一般,他人可通過(guò)分析存放在本地的并進(jìn)行欺騙。在安全性第一的前提下,選擇更優(yōu)??紤]到減輕服務(wù)器性能方面,應(yīng)當(dāng)適時(shí)使用。因此,維持一個(gè)會(huì)話的核心就是客戶端的唯一標(biāo)識(shí),即。 showImg(https://segmentfault.com/img/bV8riL?w=800&h=444); 在技術(shù)面試中,經(jīng)常被問(wèn)到說(shuō)說(shuō)Cookie和Session的區(qū)別...

    microelec 評(píng)論0 收藏0
  • 詳解 Cookie,Session,Token

    摘要:由于是存在客戶端上的,所以瀏覽器加入了一些限制確保不會(huì)被惡意使用,同時(shí)不會(huì)占據(jù)太多磁盤空間。簽名是對(duì)前兩部分的簽名,防止數(shù)據(jù)被篡改。的作用最開(kāi)始的初衷是為了實(shí)現(xiàn)授權(quán)和身份認(rèn)證作用的,可以實(shí)現(xiàn)無(wú)狀態(tài),分布式的應(yīng)用授權(quán)。 前言 無(wú)狀態(tài)的HTTP協(xié)議 很久很久之前, Web基本都是文檔的瀏覽而已。既然是瀏覽, 作為服務(wù)器, 不需要記錄在某一段時(shí)間里都瀏覽了什么文檔, 每次請(qǐng)求都是一個(gè)新的HT...

    Allen 評(píng)論0 收藏0
  • Cookiesession詳解

    摘要:協(xié)議是無(wú)狀態(tài)的,一旦數(shù)據(jù)交換完畢,客戶端與服務(wù)器端的連接就會(huì)關(guān)閉,再次交換建立新的連接,也就是說(shuō),服務(wù)器無(wú)法跟蹤會(huì)話。而和就是用與解決這種問(wèn)題。值得一提的是是建立在的基礎(chǔ)上創(chuàng)建的。注意在的文件中,設(shè)置了的生命周期最長(zhǎng)為分鐘。 在將cookie 和 session 之前需要先理解什么是會(huì)話會(huì)話: 用戶打開(kāi)一個(gè)瀏覽器,點(diǎn)擊多個(gè)超鏈接,訪問(wèn)多個(gè)web資源,然后關(guān)閉瀏覽器,整個(gè)過(guò)程稱為一個(gè)...

    wow_worktile 評(píng)論0 收藏0
  • Javascript本地存儲(chǔ)小結(jié)

    摘要:不是很安全,別人可以分析存放在本地的并進(jìn)行欺騙,考慮到安全應(yīng)當(dāng)使用。因此不是一種持久化的本地存儲(chǔ),僅僅是會(huì)話級(jí)別的存儲(chǔ)。用于持久化的本地存儲(chǔ),除非主動(dòng)刪除數(shù)據(jù),否則數(shù)據(jù)是永遠(yuǎn)不會(huì)過(guò)期的。 前言 總括:詳細(xì)講述Cookie,LocalStorge,SesstionStorge的區(qū)別和用法。 人生如畫,歲月如歌。 原文博客地址:Javascript本地存儲(chǔ)小結(jié) 知乎專欄&&簡(jiǎn)書專題:前端...

    garfileo 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<