會話(Session)跟蹤是Web程式中經常使用的技術,用來跟蹤使用者的整個會話。經常使用的會話跟蹤技術是Cookie與Session。
Cookie通過在client記錄資訊确定使用者身份,Session通過在server端記錄資訊确定使用者身份。
本章将系統地講述Cookie與Session機制,并比較說明什麼時候不能用Cookie。什麼時候不能用Session。
Cookie機制
Cookie技術是client的解決方式,Cookie就是由server發給client的特殊資訊。而這些資訊以文本檔案的方式存放在client,然後client每次向server發送請求的時候都會帶上這些特殊的資訊。
讓我們說得更詳細一些:當使用者使用浏覽器訪問一個支援Cookie的站點的時候,使用者會提供包含username在内的個人資訊而且送出至server;接着,server在向client回傳對應的超文本的同一時候也會發回這些個人資訊,當然這些資訊并非存放在HTTP響應體(Response Body)中的,而是存放于HTTP響應頭(Response Header);當client浏覽器接收到來自server的響應之後,浏覽器會将這些資訊存放在一個統一的位置。對于Windows作業系統而言,我們能夠從: [系統盤]:\Documents and Settings\[username]\Cookies檔案夾中找到存儲的Cookie;自此。client再向server發送請求的時候,都會把相應的Cookie再次發回至server。
而這次,Cookie資訊則存放在HTTP請求頭(Request Header)了。
有了Cookie這種技術實作,server在接收到來自client浏覽器的請求之後,就行通過分析存放于請求頭的Cookie得到client特有的資訊。進而動态生成與該client相相應的内容。
通常。我們可以從非常多站點的登入界面中看到“請記住我”這種選項,假設你勾選了它之後再登入,那麼在下一次訪問該站點的時候就不須要進行反複而繁瑣的登入動作了。而這個功能就是通過Cookie實作的。
在程式中,會話跟蹤是非常重要的事情。理論上。一個使用者的全部請求操作都應該屬于同一個會話。而還有一個使用者的全部請求操作則應該屬于還有一個會話。二者不能混淆。
比如。使用者A在超市購買的不論什麼商品都應該放在A的購物車内,不論是使用者A什麼時間購買的。這都是屬于同一個會話的。不能放入使用者B或使用者C的購物車内,這不屬于同一個會話。
而Web應用程式是使用HTTP協定資料傳輸的。HTTP協定是無狀态的協定。一旦資料交換完成,client與server端的連接配接就會關閉,再次交換資料須要建立新的連接配接。
這就意味着server無法從連接配接上跟蹤會話。即使用者A購買了一件商品放入購物車内。當再次購買商品時server已經無法推斷該購買行為是屬于使用者A的會話還是使用者B的會話了。要跟蹤該會話,必須引入一種機制。
Cookie就是這種一種機制。它能夠彌補HTTP協定無狀态的不足。在Session出現之前,基本上全部的站點都採用Cookie來跟蹤會話。
假設你把Cookies看成為http協定的一個擴充的話,了解起來就easy的多了。事實上本質上cookies就是http的一個擴充。
有兩個http頭部是專門負責設定以及發送cookie的,它們各自是Set-Cookie以及Cookie。當server傳回給client一個http響應資訊時,當中假設包括Set-Cookie這個頭部時。意思就是訓示client建立一個cookie。而且在興許的http請求中自己主動發送這個cookie到server端,直到這個cookie過期。
假設cookie的生存時間是整個會話期間的話,那麼浏覽器會将cookie儲存在記憶體中,浏覽器關閉時就會自己主動清除這個cookie。第二種情況就是儲存在client的硬碟中。浏覽器關閉的話,該cookie也不會被清除。下次打開浏覽器訪問相應站點時,這個cookie就會自己主動再次發送到server端。一個cookie的設定以及發送過程分為下面四步:
client發送一個http請求到server端 server端發送一個http響應到client,當中包括Set-Cookie頭部 client發送一個http請求到server端。當中包括Cookie頭部 server端發送一個http響應到client
這個通訊過程也能夠用下面下示意圖來描寫叙述:
在client的第二次請求中包括的Cookie頭部中,提供給了server端能夠用來唯一辨別client身份的資訊。這時,server端也就能夠推斷client是否啟用了cookies。
雖然,使用者可能在和應用程式互動的過程中突然禁用cookies的使用,可是,這個情況基本是不太可能發生的,是以能夠不加以考慮。這在實踐中也被證明是對的。
除了cookies,client還能夠将發送給server的資料包括在請求的url中,比方請求的參數或者請求的路徑中。
我們來看一個正常的http get 請求樣例:
GET /index.php?
foo=bar HTTP/1.1 Host: example.org
第二種client傳遞資料到server端的方式是将資料包括在http請求的内容區域内。
這樣的方式須要請求的類型是POST的。看以下一個樣例:
POST /index.php HTTP/1.1 Host: example.org Content-Type: application/x-www-form-urlencoded Content-Length: 7
foo=bar
在一個請求中。能夠同一時候包括這兩種形式的資料:
POST /index.php?myget=foo HTTP/1.1 Host: example.orgContent-Type: application/x-www-form-urlencoded Content-Length: 11
mypost=bar
這兩種傳遞資料的方式,比起用cookies來傳遞資料更穩定,由于cookie可能被禁用。可是以GET以及POST方式傳遞資料時,不存在這樣的情況。我們能夠将PHPSESSID包括在http請求的url中,就像以下的樣例一樣:
GET /index.php?PHPSESSID=12345 HTTP/1.1 Host: example.org
什麼是Cookie
Cookie意為“甜餅”。是由W3C組織提出,最早由Netscape社群發展的一種機制。眼下Cookie已經成為标準。全部的主流浏覽器如IE、Netscape、Firefox、Opera等都支援Cookie。
因為HTTP是一種無狀态的協定。server單從網絡連接配接上無從知道客戶身份。怎麼辦呢?就給client們頒發一個通行證吧,每人一個,不管誰訪問都必須攜帶自己通行證。
這樣server就能從通行證上确認客戶身份了。這就是Cookie的工作原理。
Cookie實際上是一小段的文本資訊。
client請求server。假設server須要記錄該使用者狀态。就使用response向client浏覽器頒發一個Cookie。client浏覽器會把Cookie儲存起來。
當浏覽器再請求該站點時。浏覽器把請求的網址連同該Cookie一同送出給server。server檢查該Cookie,以此來辨認使用者狀态。
server還能夠依據須要改動Cookie的内容。
檢視某個站點頒發的Cookie非常easy。在浏覽器位址欄輸入javascript:alert (document. cookie)就能夠了。JavaScript腳本會彈出一個對話框顯示本站點頒發的全部Cookie的内容。
上圖中彈出的對話框中顯示的為Baidu站點的Cookie。當中第一行BAIDUID記錄的就是筆者的身份helloweenvsfei,僅僅是Baidu使用特殊的方法将Cookie資訊加密了。
注意:Cookie功能須要浏覽器的支援。假設浏覽器不支援Cookie(如大部分手機中的浏覽器)或者把Cookie禁用了。Cookie功能就會失效。
不同的浏覽器採用不同的方式儲存Cookie。IE浏覽器會在“C:\Documents and Settings\你的username\Cookies”目錄下以文本檔案形式儲存,一個文本檔案儲存一個Cookie。
記錄使用者訪問次數
Java中把Cookie封裝成了javax.servlet.http.Cookie類。每一個Cookie都是該Cookie類的對象。server通過操作Cookie類對象對clientCookie進行操作。
通過request.getCookie()擷取client送出的全部Cookie(以Cookie[]數組形式傳回)。通過response.addCookie(Cookiecookie)向client設定Cookie。
Cookie對象使用key-value屬性對的形式儲存使用者狀态。一個Cookie對象儲存一個屬性對。一個request或者response同一時候使用多個Cookie。
由于Cookie類位于包javax.servlet.http.*以下。是以JSP中不須要import該類。
Cookie的不可跨域名性
非常多站點都會使用Cookie。
比如。Google會向client頒發Cookie。Baidu也會向client頒發Cookie。
那浏覽器訪問Google會不會也攜帶上Baidu頒發的Cookie呢?或者Google能不能改動Baidu頒發的Cookie呢?
答案是否定的。Cookie具有不可跨域名性。依據Cookie規範,浏覽器訪問Google僅僅會攜帶Google的Cookie,而不會攜帶Baidu的Cookie。Google也僅僅能操作Google的Cookie,而不能操作Baidu的Cookie。
Cookie在client是由浏覽器來管理的。浏覽器可以保證Google僅僅會操作Google的Cookie而不會操作Baidu的Cookie。進而保證使用者的隐私安全。浏覽器推斷一個站點能否操作還有一個站點Cookie的根據是域名。Google與Baidu的域名不一樣,是以Google不能操作Baidu的Cookie。
須要注意的是。盡管站點images.google.com與站點www.google.com同屬于Google,可是域名不一樣,二者相同不能互相操作彼此的Cookie。
注意:使用者登入站點www.google.com之後會發現訪問images.google.com時登入資訊仍然有效,而普通的Cookie是做不到的。這是由于Google做了特殊處理。本章後面也會對Cookie做類似的處理。
Unicode編碼:儲存中文
中文與英文字元不同,中文屬于Unicode字元,在記憶體中占4個字元。而英文屬于ASCII字元。記憶體中僅僅占2個位元組。
Cookie中使用Unicode字元時須要對Unicode字元進行編碼。否則會亂碼。
提示:Cookie中儲存中文僅僅能編碼。一般使用UTF-8編碼就可以。
不推薦使用GBK等中文編碼,由于浏覽器不一定支援。并且JavaScript也不支援GBK編碼。
BASE64編碼:儲存二進制圖檔
Cookie不僅能夠使用ASCII字元與Unicode字元,還能夠使用二進制資料。
比如在Cookie中使用數字證書。提供安全度。
使用二進制資料時也須要進行編碼。
注意:本程式僅用于展示Cookie中能夠存儲二進制内容。并不有用。因為浏覽器每次請求server都會攜帶Cookie。是以Cookie内容不宜過多,否則影響速度。Cookie的内容應該少而精。
設定Cookie的全部屬性
除了name與value之外,Cookie還具有其它幾個經常使用的屬性。每一個屬性相應一個getter方法與一個setter方法。Cookie類的全部屬性例如以下所看到的。
String name:該Cookie的名稱。Cookie一旦建立,名稱便不可更改。
Object value:該Cookie的值。
假設值為Unicode字元。須要為字元編碼。
假設值為二進制資料,則須要使用BASE64編碼。 int maxAge:該Cookie失效的時間,機關秒。
假設為正數。則該Cookie在maxAge秒之後失效。
假設為負數,該Cookie為暫時Cookie。關閉浏覽器即失效,浏覽器也不會以不論什麼形式儲存該Cookie。
假設為0。表示删除該Cookie。默覺得–1。 boolean secure:該Cookie是否僅被使用安全協定傳輸。
安全協定。安全協定有HTTPS,SSL等,在網絡上資料傳輸之前先将資料加密。默覺得false。 String path:該Cookie的使用路徑。假設設定為“/sessionWeb/”。則僅僅有contextPath為“/sessionWeb”的程式能夠訪問該Cookie。
假設設定為“/”,則本域名下contextPath都能夠訪問該Cookie。注意最後一個字元必須為“/”。 String domain:能夠訪問該Cookie的域名。假設設定為“.google.com”,則全部以“google.com”結尾的域名都能夠訪問該Cookie。注意第一個字元必須為“.”。
String comment:該Cookie的用處說明。浏覽器顯示Cookie資訊的時候顯示該說明。 int version:該Cookie使用的版本。0表示遵循Netscape的Cookie規範,1表示遵循W3C的RFC 2109規範。
Cookie的有效期
Cookie的maxAge決定着Cookie的有效期,機關為秒(Second)。Cookie中通過getMaxAge()方法與setMaxAge(int maxAge)方法來讀寫maxAge屬性。 假設maxAge屬性為正數,則表示該Cookie會在maxAge秒之後自己主動失效。浏覽器會将maxAge為正數的Cookie持久化。即寫到相應的Cookie檔案裡。
不管客戶關閉了浏覽器還是電腦,僅僅要還在maxAge秒之前,登入站點時該Cookie仍然有效。以下代碼中的Cookie資訊将永遠有效。
Cookie cookie = new Cookie("username","helloweenvsfei"); // 建立Cookie
cookie.setMaxAge(Integer.MAX_VALUE); // 設定生命周期為MAX_VALUE
response.addCookie(cookie); // 輸出到client
假設maxAge為負數,則表示該Cookie僅在本浏覽器窗體以及本窗體打開的子窗體内有效,關閉窗體後該Cookie即失效。
maxAge為負數的Cookie,為暫時性Cookie。不會被持久化,不會被寫到Cookie檔案裡。
Cookie資訊儲存在浏覽器記憶體中。是以關閉浏覽器該Cookie就消失了。Cookie預設的maxAge值為–1。
假設maxAge為0,則表示删除該Cookie。Cookie機制沒有提供删除Cookie的方法,是以通過設定該Cookie即時失效實作删除Cookie的效果。
失效的Cookie會被浏覽器從Cookie檔案或者記憶體中删除:
cookie.setMaxAge(0); // 設定生命周期為0,不能為負數
response.addCookie(cookie); // 必須運作這一句
response對象提供的Cookie操作方法僅僅有一個加入操作add(Cookie cookie)。要想改動Cookie僅僅能使用一個同名的Cookie來覆寫原來的Cookie,達到改動的目的。删除時僅僅須要把maxAge改動為0就可以。
注意:從client讀取Cookie時,包含maxAge在内的其它屬性都是不可讀的,也不會被送出。
浏覽器送出Cookie時僅僅會送出name與value屬性。maxAge屬性僅僅被浏覽器用來推斷Cookie是否過期。
Cookie的改動、删除
Cookie并不提供改動、删除操作。假設要改動某個Cookie,僅僅須要建立一個同名的Cookie。加入到response中覆寫原來的Cookie。假設要删除某個Cookie,僅僅須要建立一個同名的Cookie。并将maxAge設定為0,并加入到response中覆寫原來的Cookie。
注意是0而不是負數。
負數代表其它的意義。讀者能夠通過上例的程式進行驗證,設定不同的屬性。
注意:改動、删除Cookie時。建立的Cookie除value、maxAge之外的全部屬性,比如name、path、domain等,都要與原Cookie全然一樣。
否則。浏覽器将視為兩個不同的Cookie不予覆寫,導緻改動、删除失敗。
Cookie的域名
Cookie是不可跨域名的。域名www.google.com頒發的Cookie不會被送出到域名www.baidu.com去。這是由Cookie的隐私安全機制決定的。
隐私安全機制可以禁止站點非法擷取其它站點的Cookie。
正常情況下,同一個一級域名下的兩個二級域名如www.helloweenvsfei.com和images.helloweenvsfei.com也不能互動使用Cookie,由于二者的域名并不嚴格同樣。假設想全部helloweenvsfei.com名下的二級域名都能夠使用該Cookie,須要設定Cookie的domain參數。比如:
Cookie cookie = new Cookie("time","20080808"); // 建立Cookie
cookie.setDomain(".helloweenvsfei.com"); // 設定域名
cookie.setPath("/"); // 設定路徑
cookie.setMaxAge(Integer.MAX_VALUE); // 設定有效期
讀者能夠改動本機C:\WINDOWS\system32\drivers\etc下的hosts檔案來配置多個暫時域名,然後使用setCookie.jsp程式來設定跨域名Cookie驗證domain屬性。
注意:domain參數必須以點(“.”)開始。另外。name同樣但domain不同的兩個Cookie是兩個不同的Cookie。假設想要兩個域名全然不同的站點共同擁有Cookie,能夠生成兩個Cookie,domain屬性分别為兩個域名,輸出到client。
Cookie的路徑
domain屬性決定執行訪問Cookie的域名,而path屬性決定同意訪問Cookie的路徑(ContextPath)。比如。假設僅僅同意/sessionWeb/下的程式使用Cookie。能夠這麼寫:
cookie.setPath("/session/"); // 設定路徑
設定為“/”時同意全部路徑使用Cookie。path屬性須要使用符号“/”結尾。name同樣但domain不同的兩個Cookie也是兩個不同的Cookie。
注意:頁面僅僅能擷取它屬于的Path的Cookie。比如/session/test/a.jsp不能擷取到路徑為/session/abc/的Cookie。使用時一定要注意。
-
domain表示的是cookie所在的域,默覺得請求的位址,如網址為www.test.com/test/test.aspx。那麼domain默覺得www.test.com。
而跨域訪問,如域A為t1.test.com,域B為t2.test.com,那麼在域A生産一個令域A和域B都能訪問的cookie就要将該cookie的domain設定為.test.com。假設要在域A生産一個令域A不能訪問而域B能訪問的cookie就要将該cookie的domain設定為t2.test.com。
- path表示cookie所在的檔案夾,默覺得/。就是根檔案夾。在同一個server上有檔案夾例如以下:/test/,/test/cd/,/test/dd/,現設一個cookie1的path為/test/。cookie2的path為/test/cd/,那麼test下的全部頁面都能夠訪問到cookie1,而/test/和/test/dd/的子頁面不能訪問cookie2。這是由于cookie能讓其path路徑下的頁面訪問。
- 浏覽器會将domain和path都同樣的cookie儲存在一個檔案中,cookie間用*隔開。
Cookie的安全屬性
HTTP協定不僅是無狀态的,并且是不安全的。
使用HTTP協定的資料不經過不論什麼加密就直接在網絡上傳播。有被截獲的可能。使用HTTP協定傳輸非常機密的内容是一種隐患。
假設不希望Cookie在HTTP等非安全協定中傳輸。能夠設定Cookie的secure屬性為true。浏覽器僅僅會在HTTPS和SSL等安全協定中傳輸此類Cookie。以下的代碼設定secure屬性為true:
Cookie cookie = new Cookie("time", "20080808"); // 建立Cookie
cookie.setSecure(true); // 設定安全屬性
提示:secure屬性并不能對Cookie内容加密,因而不能保證絕對的安全性。
假設須要高安全性,須要在程式中對Cookie内容加密、解密。以防洩密。
JavaScript操作Cookie
Cookie是儲存在浏覽器端的,是以浏覽器具有操作Cookie的先決條件。
浏覽器能夠使用腳本程式如JavaScript或者VBScript等操作Cookie。
這裡以JavaScript為例介紹經常使用的Cookie操作。
比如以下的代碼會輸出本頁面全部的Cookie。
<script>document.write(document.cookie);</script>
`
因為JavaScript可以随意地讀寫Cookie,有些好事者便想使用JavaScript程式去窺探使用者在其它站點的Cookie。
隻是這是徒勞的。W3C組織早就意識到JavaScript對Cookie的讀寫所帶來的安全隐患并加以防備了,W3C标準的浏覽器會阻止JavaScript讀寫不論什麼不屬于自己站點的Cookie。換句話說,A站點的JavaScript程式讀寫B站點的Cookie不會有不論什麼結果。
案例:永久登入
假設使用者是在自己家的電腦上上網。登入時就能夠記住他的登入資訊,下次訪問時不須要再次登入,直接訪問就可以。
實作方法是把登入資訊如賬号、password等儲存在Cookie中,并控制Cookie的有效期。下次訪問時再驗證Cookie中的登入資訊就可以。
儲存登入資訊有多種方案。最直接的是把username與password都保持到Cookie中,下次訪問時檢查Cookie中的username與password,與資料庫比較。這是一種比較危急的選擇。一般不把password等重要資訊儲存到Cookie中。
另一種方案是把password加密後儲存到Cookie中,下次訪問時解密并與資料庫比較。
這樣的方案稍微安全一些。
假設不希望儲存password。還能夠把登入的時間戳儲存到Cookie與資料庫中,到時僅僅驗證username與登入時間戳就能夠了。
這幾種方案驗證賬号時都要查詢資料庫。
本例将採用還有一種方案,僅僅在登入時查詢一次資料庫。以後訪問驗證登入資訊時不再查詢資料庫。實作方式是把賬号依照一定的規則加密後。連同賬号一塊儲存到Cookie中。下次訪問時僅僅須要推斷賬号的加密規則是否正确就可以。
本例把賬号儲存到名為account的Cookie中,把賬号連同密鑰用MD1算法加密後儲存到名為ssid的Cookie中。驗證時驗證Cookie中的賬号與密鑰加密後是否與Cookie中的ssid相等。相關代碼例如以下: loginCookie.jsp:
<%@ page language="java" pageEncoding="UTF-8" isErrorPage="false" %>
<%! // JSP方法
private static final String KEY =":[email protected]"; // 密鑰
public final static String calcMD1(String ss) { // 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(); // 擷取位元組
MessageDigestmdTemp = MessageDigest.getInstance("MD1"); // 擷取MD1
mdTemp.update(strTemp); // 更新資料
byte[] md =mdTemp.digest(); // 加密
int j =md.length; // 加密後的長度
char str[] = new char[j * 2]; // 新字元串數組
int k =0; // 計數器k
for (int i = 0; i< j; i++) { // 循環輸出
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
return new String(str); // 加密後字元串
} catch (Exception e){return null; }
}
%>
<%
request.setCharacterEncoding("UTF-8"); // 設定request編碼
response.setCharacterEncoding("UTF-8"); // 設定response編碼
String action =request.getParameter("action"); // 擷取action參數
if("login".equals(action)) { // 假設為login動作
String account =request.getParameter("account"); // 擷取account參數
String password =request.getParameter("password"); // 擷取password參數
int timeout = new Integer(request.getParameter("timeout")); // 擷取timeout參數
String ssid =calcMD1(account + KEY); // 把賬号、密鑰使用MD1加密後儲存
Cookie accountCookie = new Cookie("account", account); // 建立Cookie
accountCookie.setMaxAge(timeout); // 設定有效期
Cookie ssidCookie =new Cookie("ssid", ssid); // 建立Cookie
ssidCookie.setMaxAge(timeout); // 設定有效期
response.addCookie(accountCookie); // 輸出到client
response.addCookie(ssidCookie); // 輸出到client
// 又一次請求本頁面。參數中帶有時間戳,禁止浏覽器緩存頁面内容
response.sendRedirect(request.getRequestURI() + "?" + System.currentTimeMillis());
return;
} else if("logout".equals(action)) { // 假設為logout動作
CookieaccountCookie = new Cookie("account", ""); // 建立Cookie,内容為空
accountCookie.setMaxAge(0); // 設定有效期為0,删除
Cookie ssidCookie =new Cookie("ssid", ""); // 建立Cookie。内容為空
ssidCookie.setMaxAge(0); // 設定有效期為0,删除
response.addCookie(accountCookie); // 輸出到client
response.addCookie(ssidCookie); // 輸出到client
response.sendRedirect(request.getRequestURI() + "?
" + System.currentTimeMillis());
boolean login = false; // 是否登入
String account = null; // 賬号
String ssid = null; // SSID辨別
if(request.getCookies() !=null) { // 假設Cookie不為空
for(Cookie cookie : request.getCookies()) { // 周遊Cookie
if(cookie.getName().equals("account")) // 假設Cookie名為 account
account = cookie.getValue(); // 儲存account内容
if(cookie.getName().equals("ssid")) // 假設為SSID
ssid = cookie.getValue(); // 儲存SSID内容
}
if(account != null && ssid !=null) { // 假設account、SSID都不為空
login = ssid.equals(calcMD1(account + KEY)); // 假設加密規則正确, 則視為已經登入
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01Transitional//EN">
<legend><%= login ? "歡迎您回來" : "請先登入"%></legend>
<% if(login){%>
歡迎您, ${cookie.account.value }.
<a href="${pageContext.request.requestURI }?action=logout">
登出</a>
<% } else { %>
<form action="${ pageContext.request.requestURI }?
action=login" method="post">
<table>
<tr><td>賬号: </td>
<td><input type="text"name="account" style="width:
200px; "></td>
</tr>
<tr><td>password: </td>
<td><inputtype="password" name="password"></td>
<tr>
<td>有效期: </td>
<td><inputtype="radio" name="timeout" value="-1"
checked> 關閉浏覽器即失效 <input type="radio"
name="timeout" value="<%= 30 *24 * 60 * 60 %>"> 30天
内有效 <input type="radio" name="timeout" value=
"<%= Integer.MAX_VALUE %>"> 永久有效 </td> </tr>
<tr><td></td>
<td><input type="submit"value=" 登 錄 " class=
"button"></td>
</table>
</form>
<% } %>
登入時能夠選擇登入資訊的有效期:關閉浏覽器即失效、30天内有效與永久有效。通過設定Cookie的age屬性來實作,注意觀察代碼。
提示:該加密機制中最重要的部分為算法與密鑰。因為MD1算法的不可逆性,即使使用者知道了賬号與加密後的字元串,也不可能解密得到密鑰。是以,僅僅要保管好密鑰與算法,該機制就是安全的。