国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

正確優(yōu)雅的解決用戶退出問(wèn)題(轉(zhuǎn)自http://www.jdon.com)

2019-11-18 11:21:27
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

wolfmanchen 翻譯javaworld.com上名為<<Solving the logout PRoblem properly and elegantly>>的文章
原文地址: http://www.javaworld.com/javaworld/jw-09-2004/jw-0927-logout.Html

正確優(yōu)雅的解決用戶退出問(wèn)題——jsp和Struts解決方案

摘要
在一個(gè)有密碼保護(hù)的Web應(yīng)用中,正確處理用戶退出過(guò)程并不僅僅只需調(diào)用Httpsession的invalidate()方法。現(xiàn)在大部分瀏覽器上都有后退和前進(jìn)按鈕,答應(yīng)用戶后退或前進(jìn)到一個(gè)頁(yè)面。假如在用戶在退出一個(gè)Web應(yīng)用后按了后退按鈕瀏覽器把緩存中的頁(yè)面呈現(xiàn)給用戶,這會(huì)使用戶產(chǎn)生迷惑,他們會(huì)開(kāi)始擔(dān)心他們的個(gè)人數(shù)據(jù)是否安全。許多Web應(yīng)用強(qiáng)迫用戶退出時(shí)關(guān)閉整個(gè)瀏覽器,這樣,用戶就無(wú)法點(diǎn)擊后退按鈕了。還有一些使用javascript,但在某些客戶端瀏覽器這卻不一定起作用。這些解決方案都很笨拙且不能保證在任一情況下100%有效,同時(shí),它也要求用戶有一定的操作經(jīng)驗(yàn)。
這篇文章以示例闡述了正確解決用戶退出問(wèn)題的方案。作者Kevin Le首先描述了一個(gè)密碼保護(hù)Web應(yīng)用,然后以示例程序解釋問(wèn)題如何產(chǎn)生并討論解決問(wèn)題的方案。文章雖然是針對(duì)JSP頁(yè)面進(jìn)行闡述,但作者所闡述的概念很輕易理解切能夠?yàn)槠渌鸚eb技術(shù)所采用。最后作者展示了如何用Jakarta Struts優(yōu)雅地解決這一問(wèn)題。




大部分Web應(yīng)用不會(huì)包含象銀行賬戶或信用卡資料那樣機(jī)密的信息,但一旦涉及到敏感數(shù)據(jù),我們就需要提供一類(lèi)密碼保護(hù)機(jī)制。舉例來(lái)說(shuō),一個(gè)工廠中工人通過(guò)Web訪問(wèn)他們的時(shí)間安排、進(jìn)入他們的練習(xí)課程以及查看他們的薪金等等。此時(shí)應(yīng)用SSL(Secure Socket Layer)有點(diǎn)殺雞用牛刀的感覺(jué),但不可否認(rèn),我們又必須為這些應(yīng)用提供密碼保護(hù),否則,工人(也就是Web應(yīng)用的使用者)可以窺探到工廠中其他雇員的私人機(jī)密信息。
與上述情形相似的還有位處圖書(shū)館、醫(yī)院等公共場(chǎng)所的計(jì)算機(jī)。在這些地方,許多用戶共同使用幾臺(tái)計(jì)算機(jī),此時(shí)保護(hù)用戶的個(gè)人數(shù)據(jù)就顯得至關(guān)重要。設(shè)計(jì)良好編寫(xiě)優(yōu)秀的應(yīng)用對(duì)用戶專(zhuān)業(yè)知識(shí)的要求少之又少。
我們來(lái)看一下現(xiàn)實(shí)世界中一個(gè)完美的Web應(yīng)用是如何表現(xiàn)的:一個(gè)用戶通過(guò)瀏覽器訪問(wèn)一個(gè)頁(yè)面。Web應(yīng)用展現(xiàn)一個(gè)登陸頁(yè)面要求用戶輸入有效的驗(yàn)證信息。用戶輸入了用戶名和密碼。此時(shí)我們假設(shè)用戶提供的身份驗(yàn)證信息是正確的,經(jīng)過(guò)了驗(yàn)證過(guò)程,Web應(yīng)用答應(yīng)用戶瀏覽他有權(quán)訪問(wèn)的區(qū)域。用戶想退出時(shí),點(diǎn)擊退出按鈕,Web應(yīng)用要求用戶確認(rèn)他是否則真的需要退出,假如用戶確定退出,Session結(jié)束,Web應(yīng)用重新定位到登陸頁(yè)面。用戶可以放心的離開(kāi)而不用擔(dān)心他的信息會(huì)泄露。另一個(gè)用戶坐到了同一臺(tái)電腦前,他點(diǎn)擊后退按鈕,Web應(yīng)用不應(yīng)該出現(xiàn)上一個(gè)用戶訪問(wèn)過(guò)的任何一個(gè)頁(yè)面。事實(shí)上,Web應(yīng)用在第二個(gè)用戶提供正確的驗(yàn)證信息之前應(yīng)當(dāng)一直停留在登陸頁(yè)面上。
通過(guò)示例程序,文章向您闡述了如何在一個(gè)Web應(yīng)用中實(shí)現(xiàn)這一功能。

JSP samples
為了更為有效地闡述實(shí)現(xiàn)方案,本文將從展示一個(gè)示例應(yīng)用logoutSampleJSP1中碰到的問(wèn)題開(kāi)始。這個(gè)示例代表了許多沒(méi)有正確解決退出過(guò)程的Web應(yīng)用。logoutSampleJSP1包含了下述jsp頁(yè)面:login.jsp, home.jsp, secure1.jsp, secure2.jsp, logout.jsp, loginAction.jsp, and logoutAction.jsp。其中頁(yè)面home.jsp, secure1.jsp, secure2.jsp, 和logout.jsp是不答應(yīng)未經(jīng)認(rèn)證的用戶訪問(wèn)的,也就是說(shuō),這些頁(yè)面包含了重要信息,在用戶登陸之前或者退出之后都不應(yīng)該出現(xiàn)在瀏覽器中。login.jsp包含了用于用戶輸入用戶名和密碼的form。logout.jsp頁(yè)包含了要求用戶確認(rèn)是否退出的form。loginAction.jsp和logoutAction.jsp作為控制器分別包含了登陸和退出代碼。
第二個(gè)示例應(yīng)用logoutSampleJSP2展示了如何解決示例logoutSampleJSP1中的問(wèn)題。然而,第二個(gè)應(yīng)用自身也是有疑問(wèn)的。在特定的情況下,退出問(wèn)題還是會(huì)出現(xiàn)。
第三個(gè)示例應(yīng)用logoutSampleJSP3在第二個(gè)示例上進(jìn)行了改進(jìn),比較完善地解決了退出問(wèn)題。
最后一個(gè)示例logoutSampleStruts展示了Struts如何美麗地解決登陸問(wèn)題。
注重:本文所附示例在最新版本的Microsoft Internet EXPlorer (IE), Netscape Navigator, Mozilla, Firefox和Avant瀏覽器上測(cè)試通過(guò)。

Login action
Brian Pontarelli的經(jīng)典文章《J2EE Security: Container Versus Custom》討論了不同的J2EE認(rèn)證途徑。文章同時(shí)指出,HTTP協(xié)議和基于form的認(rèn)證并未提供處理用戶退出的機(jī)制。因此,解決途徑便是引入自定義的安全實(shí)現(xiàn)機(jī)制。
自定義的安全認(rèn)證機(jī)制普遍采用的方法是從form中獲得用戶輸入的認(rèn)證信息,然后到諸如LDAP (lightweight Directory access protocol)或關(guān)系數(shù)據(jù)庫(kù)的安全域中進(jìn)行認(rèn)證。假如用戶提供的認(rèn)證信息是有效的,登陸動(dòng)作往HttpSession對(duì)象中注入某個(gè)對(duì)象。HttpSession存在著注入的對(duì)象則表示用戶已經(jīng)登陸。為了方便讀者理解,本文所附的示例只往HttpSession中寫(xiě)入一個(gè)用戶名以表明用戶已經(jīng)登陸。清單1是從loginAction.jsp頁(yè)面中節(jié)選的一段代碼以此闡述登陸動(dòng)作:




Listing 1
//...
//initialize RequestDispatcher object; set forward to home page by default
RequestDispatcher rd = request.getRequestDispatcher("home.jsp");

//Prepare connection and statement
rs = stmt.executeQuery("select passWord from USER where userName = '" + userName + "'");
if (rs.next()) { //Query only returns 1 record in the result set; only 1
password per userName which is also the primary key
if (rs.getString("password").equals(password)) { //If valid password
session.setAttribute("User", userName); //Saves username string in the session object
}
else { //Password does not match, i.e., invalid user password
request.setAttribute("Error", "Invalid password.");

rd = request.getRequestDispatcher("login.jsp");
}
} //No record in the result set, i.e., invalid username
else {

request.setAttribute("Error", "Invalid user name.");
rd = request.getRequestDispatcher("login.jsp");
}
}

//As a controller, loginAction.jsp finally either forwards to "login.jsp" or "home.jsp"
rd.forward(request, response);
//...


本文所附示例均以關(guān)系型數(shù)據(jù)庫(kù)作為安全域,但本問(wèn)所闡述的觀點(diǎn)對(duì)任何類(lèi)型的安全域都是適用的。

Logout action
退出動(dòng)作就包含了簡(jiǎn)單的刪除用戶名以及對(duì)用戶的HttpSession對(duì)象調(diào)用invalidate()方法。清單2是從loginoutAction.jsp頁(yè)面中節(jié)選的一段代碼以此闡述退出動(dòng)作:



Listing 2
//...
session.removeAttribute("User");
session.invalidate();
//...


阻止未經(jīng)認(rèn)證訪問(wèn)受保護(hù)的JSP頁(yè)面
從form中獲取用戶提交的認(rèn)證信息并經(jīng)過(guò)驗(yàn)證后,登陸動(dòng)作簡(jiǎn)單地往 HttpSession對(duì)象中寫(xiě)入一個(gè)用戶名,退出動(dòng)作則做相反的工作,它從用戶的HttpSession對(duì)象中刪除用戶名并調(diào)用invalidate()方法銷(xiāo)毀HttpSession。為了使登陸和退出動(dòng)作真正發(fā)揮作用,所有受保護(hù)的JSP頁(yè)面都應(yīng)該首先驗(yàn)證HttpSession中是否包含了用戶名以確認(rèn)當(dāng)前用戶是否已經(jīng)登陸。假如HttpSession中包含了用戶名,也就是說(shuō)用戶已經(jīng)登陸,Web應(yīng)用則將剩余的JSP頁(yè)發(fā)送給瀏覽器,否則,JSP頁(yè)將跳轉(zhuǎn)到登陸頁(yè)login.jsp。頁(yè)面home.jsp, secure1.jsp, secure2.jsp和logout.jsp均包含清單3中的代碼段:


Listing 3
//...
String userName = (String) session.getAttribute("User");
if (null == userName) {
request.setAttribute("Error", "Session has ended. Please login.");
RequestDispatcher rd = request.getRequestDispatcher("login.jsp");
rd.forward(request, response);
}
//...
//Allow the rest of the dynamic content in this JSP to be served to the browser
//...


在這個(gè)代碼段中,程序從HttpSession中減縮username字符串。假如字符串為空,Web應(yīng)用則自動(dòng)中止執(zhí)行當(dāng)前頁(yè)面并跳轉(zhuǎn)到登陸頁(yè),同時(shí)給出Session has ended. Please log in.的提示;假如不為空,Web應(yīng)用則繼續(xù)執(zhí)行,也就是把剩余的頁(yè)面提供給用戶。
運(yùn)行l(wèi)ogoutSampleJSP1
運(yùn)行l(wèi)ogoutSampleJSP1將會(huì)出現(xiàn)如下幾種情形:
• 假如用戶沒(méi)有登陸,Web應(yīng)用將會(huì)正確中止受保護(hù)頁(yè)面home.jsp, secure1.jsp, secure2.jsp和logout.jsp的執(zhí)行,也就是說(shuō),假如用戶在瀏覽器地址欄中直接敲入受保護(hù)JSP頁(yè)的地址試圖訪問(wèn),Web應(yīng)用將自動(dòng)跳轉(zhuǎn)到登陸頁(yè)并提示Session has ended.Please log in.
• 同樣的,當(dāng)一個(gè)用戶已經(jīng)退出,Web應(yīng)用也會(huì)正確中止受保護(hù)頁(yè)面home.jsp, secure1.jsp, secure2.jsp和logout.jsp的執(zhí)行
• 用戶退出后,假如點(diǎn)擊瀏覽器上的后退按鈕,Web應(yīng)用將不能正確保護(hù)受保護(hù)的頁(yè)面——在Session銷(xiāo)毀后(用戶退出)受保護(hù)的JSP頁(yè)重新在瀏覽器中顯示出來(lái)。然而,假如用戶點(diǎn)擊返回頁(yè)面上的任何鏈接,Web應(yīng)用將會(huì)跳轉(zhuǎn)到登陸頁(yè)面并提示Session has ended.Please log in.
阻止瀏覽器緩存
上述問(wèn)題的根源在于大部分瀏覽器都有一個(gè)后退按鈕。當(dāng)點(diǎn)擊后退按鈕時(shí),默認(rèn)情況下瀏覽器不是從Web服務(wù)器上重新獲取頁(yè)面,而是從瀏覽器緩存中載入頁(yè)面?;贘ava的Web應(yīng)用并未限制這一功能,在基于php、asp和.NET的Web應(yīng)用中也同樣存在這一問(wèn)題。
在用戶點(diǎn)擊后退按鈕后,瀏覽器到服務(wù)器再?gòu)姆?wù)器到瀏覽器這樣通常意思上的HTTP回路并沒(méi)有建立,僅僅只是用戶,瀏覽器和緩存進(jìn)行了交互。所以,即使包含了清單3上的代碼來(lái)保護(hù)JSP頁(yè)面,當(dāng)點(diǎn)擊后退按鈕時(shí),這些代碼是不會(huì)執(zhí)行的。
緩存的好壞,真是仁者見(jiàn)仁智者見(jiàn)智。緩存的確提供了一些便利,但通常只在使用靜態(tài)的HTML頁(yè)面或基于圖形或影響的頁(yè)面你才能感受到。而另一方面,Web應(yīng)用通常是基于數(shù)據(jù)的,數(shù)據(jù)通常是頻繁更改的。與從緩存中讀取并顯示過(guò)期的數(shù)據(jù)相比,提供最新的數(shù)據(jù)才是更重要的!
幸運(yùn)的是,HTTP頭信息“Expires”和“Cache-Control”為應(yīng)用程序服務(wù)器提供了一個(gè)控制瀏覽器和代理服務(wù)器上緩存的機(jī)制。HTTP頭信息Expires告訴代理服務(wù)器它的緩存頁(yè)面何時(shí)將過(guò)期。HTTP1.1規(guī)范中新定義的頭信息Cache-Control可以通知瀏覽器不緩存任何頁(yè)面。當(dāng)點(diǎn)擊后退按鈕時(shí),瀏覽器重新訪問(wèn)服務(wù)器已獲取頁(yè)面。如下是使用Cache-Control的基本方法:
• no-cache:強(qiáng)制緩存從服務(wù)器上獲取新的頁(yè)面
• no-store: 在任何環(huán)境下緩存不保存任何頁(yè)面
HTTP1.0規(guī)范中的Pragma:no-cache等同于HTTP1.1規(guī)范中的Cache-Control:no-cache,同樣可以包含在頭信息中。
通過(guò)使用HTTP頭信息的cache控制,第二個(gè)示例應(yīng)用logoutSampleJSP2解決了logoutSampleJSP1的問(wèn)題。logoutSampleJSP2與logoutSampleJSP1不同表現(xiàn)在如下代碼段中,這一代碼段加入進(jìn)所有受保護(hù)的頁(yè)面中:




//...
response.setHeader("Cache-Control","no-cache"); //Forces caches to oBTain a new copy of the page from the origin server
response.setHeader("Cache-Control","no-store"); //Directs caches not to store the page under any circumstance
response.setDateHeader("Expires", 0); //Causes the proxy cache to see the page as "stale"
response.setHeader("Pragma","no-cache"); //HTTP 1.0 backward compatibility
String userName = (String) session.getAttribute("User");
if (null == userName) {
request.setAttribute("Error", "Session has ended. Please login.");
RequestDispatcher rd = request.getRequestDispatcher("login.jsp");
rd.forward(request, response);
}
//...


通過(guò)設(shè)置頭信息和檢查HttpSession中的用戶名確保了瀏覽器不緩存頁(yè)面,同時(shí),假如用戶未登陸,受保護(hù)的JSP頁(yè)面將不會(huì)發(fā)送到瀏覽器,取而代之的將是登陸頁(yè)面login.jsp。
運(yùn)行l(wèi)ogoutSampleJSP2
運(yùn)行l(wèi)ogoutSampleJSP2后將回看到如下結(jié)果:
• 當(dāng)用戶退出后試圖點(diǎn)擊后退按鈕,瀏覽器并不會(huì)顯示受保護(hù)的頁(yè)面,它只會(huì)現(xiàn)實(shí)登陸頁(yè)login.jsp同時(shí)給出提示信息Session has ended. Please log in.
• 然而,當(dāng)按了后退按鈕返回的頁(yè)是處理用戶提交數(shù)據(jù)的頁(yè)面時(shí),IE和Avant瀏覽器將彈出如下信息提示:
警告:頁(yè)面已過(guò)期……(你肯定見(jiàn)過(guò))
選擇刷新后前一個(gè)JSP頁(yè)面將重新顯示在瀏覽器中。很顯然,這不是我們所想看到的因?yàn)樗`反了logout動(dòng)作的目的。發(fā)生這一現(xiàn)象時(shí),很可能是一個(gè)惡意用戶在嘗試獲取其他用戶的數(shù)據(jù)。然而,這個(gè)問(wèn)題僅僅出現(xiàn)在后退按鈕對(duì)應(yīng)的是一個(gè)處理POST請(qǐng)求的頁(yè)面。
記錄最后登陸時(shí)間
上述問(wèn)題之所以出現(xiàn)是因?yàn)闉g覽器將其緩存中的數(shù)據(jù)重新提交了。這本文的例子中,數(shù)據(jù)包含了用戶名和密碼。無(wú)論是否給出安全警告信息,瀏覽器此時(shí)起到了負(fù)面作用。
為了解決logoutSampleJSP2中出現(xiàn)的問(wèn)題,logoutSampleJSP3的login.jsp在包含username和password的基礎(chǔ)上還包含了一個(gè)稱(chēng)作lastLogon的隱藏表單域,此表單域動(dòng)態(tài)的用一個(gè)long型值初始化。這個(gè)long型值是調(diào)用System.currentTimeMillis()獲取到的自1970年1月1日以來(lái)的毫秒數(shù)。當(dāng)login.jsp中的form提交時(shí),loginAction.jsp首先將隱藏域中的值與用戶數(shù)據(jù)庫(kù)中的值進(jìn)行比較。只有當(dāng)lastLogon表單域中的值大于數(shù)據(jù)庫(kù)中的值時(shí)Web應(yīng)用才認(rèn)為這是個(gè)有效的登陸。
為了驗(yàn)證登陸,數(shù)據(jù)庫(kù)中l(wèi)astLogon字段必須以表單中的lastLogon值進(jìn)行更新。上例中,當(dāng)瀏覽器重復(fù)提交數(shù)據(jù)時(shí),表單中的lastLogon值不比數(shù)據(jù)庫(kù)中的lastLogon值大,因此,loginAction轉(zhuǎn)到login.jsp頁(yè)面,并提示Session has ended.Please log in.清單5是loginAction中節(jié)選的代碼段:




清單5
//...
RequestDispatcher rd = request.getRequestDispatcher("home.jsp"); //Forward to homepage by default
//...
if (rs.getString("password").equals(password)) { //If valid password
long lastLogonDB = rs.getLong("lastLogon");
if (lastLogonForm > lastLogonDB) {
session.setAttribute("User", userName); //Saves username string in the session object
stmt.executeUpdate("update USER set lastLogon= " + lastLogonForm + " where userName = '" + userName + "'");
}
else {
request.setAttribute("Error", "Session has ended. Please login.");
rd = request.getRequestDispatcher("login.jsp"); }
}
else { //Password does not match, i.e., invalid user password
request.setAttribute("Error", "Invalid password.");
rd = request.getRequestDispatcher("login.jsp");
}
//...
rd.forward(request, response);
//...


為了實(shí)現(xiàn)上述方法,你必須記錄每個(gè)用戶的最后登陸時(shí)間。對(duì)于采用關(guān)系型數(shù)據(jù)庫(kù)安全域來(lái)說(shuō),這點(diǎn)可以可以通過(guò)在某個(gè)表中加上lastLogin字段輕松實(shí)現(xiàn)。LDAP以及其他的安全域需要稍微動(dòng)下腦筋,但很顯然是可以實(shí)現(xiàn)的。
表示最后登陸時(shí)間的方法有很多。示例logoutSampleJSP3利用了自1970年1月1日以來(lái)的毫秒數(shù)。這個(gè)方法在許多人在不同瀏覽器中用一個(gè)用戶賬號(hào)登陸時(shí)也是可行的。
運(yùn)行l(wèi)ogoutSampleJSP3
運(yùn)行示例logoutSampleJSP3將展示如何正確處理退出問(wèn)題。一旦用戶退出,點(diǎn)擊瀏覽器上的后退按鈕在任何情況下都不會(huì)是受保護(hù)的頁(yè)面在瀏覽器上顯示出來(lái)。這個(gè)示例展示了如何正確處理退出問(wèn)題而不需要額外的培訓(xùn)。
為了使代碼更簡(jiǎn)練有效,一些冗余的代碼可以剔除掉。一種途徑就是把清單4中的代碼寫(xiě)到一個(gè)單獨(dú)的JSP頁(yè)中,通過(guò)標(biāo)簽其他頁(yè)面也可以引用。
Struts框架下的退出實(shí)現(xiàn)
與直接使用JSP或JSP/servlets相比,另一個(gè)可選的方案是使用Struts。為一個(gè)基于Struts的Web應(yīng)用添加一個(gè)處理退出問(wèn)題的框架可以優(yōu)雅地不費(fèi)氣力的實(shí)現(xiàn)。這部分歸功于Struts是采用MVC設(shè)計(jì)模式的因此將模型和視圖清楚的分開(kāi)。另外,Java是一個(gè)面向?qū)ο蟮恼Z(yǔ)言,其支持繼續(xù),可以比JSP中的腳本更為輕易地實(shí)現(xiàn)代碼重用。在Struts中,清單4中的代碼可以從JSP頁(yè)面中移植到Action類(lèi)的execute()方法中。
此外,我們還可以定義一個(gè)繼續(xù)Struts Action類(lèi)的基本類(lèi),其execute()方法中包含了清單4中的代碼。通過(guò)使用類(lèi)繼續(xù)機(jī)制,其他類(lèi)可以繼續(xù)基本類(lèi)中的通用邏輯來(lái)設(shè)置HTTP頭信息以及檢索HttpSession對(duì)象中的username字符串。這個(gè)基本類(lèi)是一個(gè)抽象類(lèi)并定義了一個(gè)抽象方法executeAction()。所有繼續(xù)自基類(lèi)的子類(lèi)都應(yīng)實(shí)現(xiàn)exectuteAction()方法而不是覆蓋它。清單6是基類(lèi)的部分代碼:



清單6
public abstract class BaseAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {

response.setHeader("Cache-Control","no-cache"); //Forces caches to obtain a new copy of the page from the origin server
response.setHeader("Cache-Control","no-store"); //Directs caches not to store the page under any circumstance
response.setDateHeader("Expires", 0); //Causes the proxy cache to see the page as "stale"
response.setHeader("Pragma","no-cache"); //HTTP 1.0 backward compatibility

if (!this.userIsLoggedIn(request)) {
ActionErrors errors = new ActionErrors();

errors.add("error", new ActionError("logon.sessionEnded"));
this.saveErrors(request, errors);

return mapping.findForward("sessionEnded");
}

return executeAction(mapping, form, request, response);
}

protected abstract ActionForward executeAction(ActionMapping mapping,
ActionForm form, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException;

private boolean userIsLoggedIn(HttpServletRequest request) {
if (request.getSession().getAttribute("User") == null) {
return false;
}

return true;
}
}


清單6中的代碼與清單4中的很相像,僅僅只是用ActionMapping findForward替代了RequestDispatcher forward。清單6中,假如在HttpSession中未找到username字符串,ActionMapping對(duì)象將找到名為sessionEnded的forward元素并跳轉(zhuǎn)到對(duì)應(yīng)的path。假如找到了,子類(lèi)將執(zhí)行其實(shí)現(xiàn)了executeAction()方法的業(yè)務(wù)邏輯。因此,在配置文件struts-web.xml中為所有子類(lèi)聲明個(gè)一名為sessionEnded的forward元素是必須的。清單7以secure1 action闡明了這樣一個(gè)聲明:


清單7
<action path="/secure1"
type="com.kevinhle.logoutSampleStruts.Secure1Action"
scope="request">
<forward name="sUCcess" path="/WEB-INF/jsps/secure1.jsp"/>
<forward name="sessionEnded" path="/login.jsp"/>
</action>



繼續(xù)自BaseAction類(lèi)的子類(lèi)Secure1Action實(shí)現(xiàn)了executeAction()方法而不是覆蓋它。Secure1Action類(lèi)不執(zhí)行任何退出代碼,如清單8:



清單8
public class Secure1Action extends BaseAction {
public ActionForward executeAction(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {

HttpSession session = request.getSession();
return (mapping.findForward("success"));
}
}


只需要定義一個(gè)基類(lèi)而不需要額外的代碼工作,上述解決方案是優(yōu)雅而有效的。不管怎樣,將通用的行為方法寫(xiě)成一個(gè)繼續(xù)StrutsAction的基類(lèi)是許多Struts項(xiàng)目的共同經(jīng)驗(yàn),值得推薦。
局限性
上述解決方案對(duì)JSP或基于Struts的Web應(yīng)用都是非常簡(jiǎn)單而實(shí)用的,但它還是有某些局限。在我看來(lái),這些局限并不是至關(guān)緊要的。
結(jié)論
本文闡述了解決退出問(wèn)題的方案,盡管方案簡(jiǎn)單的令人驚奇,但卻在所有情況下都能有效地工作。無(wú)論是對(duì)JSP還是Struts,所要做的不過(guò)是寫(xiě)一段不超過(guò)50行的代碼以及一個(gè)記錄用戶最后登陸時(shí)間的方法。在Web應(yīng)用中混合使用這些方案能夠使擁護(hù)的私人數(shù)據(jù)不致泄露,同時(shí),也能增加用戶的經(jīng)驗(yàn)。

About the author
Kevin H. Le has more than 12 years of experience in software development. In the first half of his career, his programming language of choice was C++. In 1997, he shifted his focus to Java. He has engaged in and successfully completed several J2EE and EAI projects as both developer and architect. In addition to J2EE, his current interests now include Web services and SOA. More information on Kevin can be found on his Website http://kevinhle.com.



發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 保康县| 广西| 鸡东县| 德阳市| 凤山县| 漳平市| 广安市| 合川市| 高邮市| 亳州市| 上林县| 南溪县| 盱眙县| 营山县| 玉环县| 吉木乃县| 平塘县| 新巴尔虎右旗| 双鸭山市| 慈溪市| 平果县| 上犹县| 类乌齐县| 南部县| 融水| 温宿县| 东阿县| 白水县| 西贡区| 临西县| 吉木乃县| 武隆县| 太和县| 景谷| 临高县| 康保县| 云林县| 交口县| 上杭县| 保靖县| 绥芬河市|