JSP和Struts解決用戶退出問題
更新時間: 2007-05-10 14:19:20來源: 粵嵌教育瀏覽量:878
在一個有密碼保護的Web應用中,正確處理用戶退出過程并不僅僅只需調用HttpSession的invalidate()方法。現(xiàn)在大部分瀏覽器上都有后退和前進按鈕,允許用戶后退或前進到一個頁面。如果在用戶在退出一個Web應用后按了后退按鈕瀏覽器把緩存中的頁面呈現(xiàn)給用戶,這會使用戶產生疑惑,他們會開始擔心他們的個人數(shù)據(jù)是否安全。許多Web應用強迫用戶退出時關閉整個瀏覽器,這樣,用戶就無法點擊后退按鈕了。還有一些使用javascript,但在某些客戶端瀏覽器這卻不一定起作用。這些解決方案都很笨拙且不能保證在任一情況下有效,同時,它也要求用戶有一定的操作經(jīng)驗。
這篇文章以示例闡述了正確解決用戶退出問題的方案。作者Kevin Le首先描述了一個密碼保護Web應用,然后以示例程序解釋問題如何產生并討論解決問題的方案。文章雖然是針對JSP頁面進行闡述,但作者所闡述的概念很容易理解切能夠為其他Web技術所采用。作者展示了如何用Jakarta Struts優(yōu)雅地解決這一問題。
大部分Web應用不會包含象銀行賬戶或信用卡資料那樣機密的信息,但一旦涉及到敏感數(shù)據(jù),我們就需要提供一類密碼保護機制。舉例來說,一個工廠中工人通過Web訪問他們的時間安排、進入他們的訓練課程以及查看他們的薪金等等。此時應用SSL(Secure Socket Layer)有點殺雞用牛刀的感覺,但不可否認,我們又必須為這些應用提供密碼保護,否則,工人(也就是Web應用的使用者)可以窺探到工廠中其他雇員的私人機密信息。
與上述情形相似的還有位處圖書館、醫(yī)院等公共場所的計算機。在這些地方,許多用戶共同使用幾臺計算機,此時保護用戶的個人數(shù)據(jù)就顯得至關重要。設計良好編寫的應用對用戶專業(yè)知識的要求少之又少。
我們來看一下現(xiàn)實世界中一個完美的Web應用是如何表現(xiàn)的:一個用戶通過瀏覽器訪問一個頁面。Web應用展現(xiàn)一個登陸頁面要求用戶輸入有效的驗證信息。用戶輸入了用戶名和密碼。此時我們假設用戶提供的身份驗證信息是正確的,經(jīng)過了驗證過程,Web應用允許用戶瀏覽他有權訪問的區(qū)域。用戶想退出時,點擊退出按鈕,Web應用要求用戶確認他是否則真的需要退出,如果用戶確定退出,Session結束,Web應用重新定位到登陸頁面。用戶可以放心的離開而不用擔心他的信息會泄露。另一個用戶坐到了同一臺電腦前,他點擊后退按鈕,Web應用不應該出現(xiàn)上一個用戶訪問過的任何一個頁面。事實上,Web應用在第二個用戶提供正確的驗證信息之前應當一直停留在登陸頁面上。
通過示例程序,文章向您闡述了如何在一個Web應用中實現(xiàn)這一功能。
JSP示例
為了更為有效地闡述實現(xiàn)方案,本文將從展示一個示例應用logoutSampleJSP1中碰到的問題開始。這個示例代表了許多沒有正確解決退出過程的Web應用。logoutSampleJSP1包含了下述jsp頁面:login.jsp, home.jsp, secure1.jsp, secure2.jsp, logout.jsp, loginAction.jsp, and logoutAction.jsp。其中頁面home.jsp, secure1.jsp, secure2.jsp, 和logout.jsp是不允許未經(jīng)認證的用戶訪問的,也就是說,這些頁面包含了重要信息,在用戶登陸之前或者退出之后都不應該出現(xiàn)在瀏覽器中。login.jsp包含了用于用戶輸入用戶名和密碼的form。logout.jsp頁包含了要求用戶確認是否退出的form。loginAction.jsp和logoutAction.jsp作為控制器分別包含了登陸和退出代碼。
第二個示例應用logoutSampleJSP2展示了如何解決示例logoutSampleJSP1中的問題。然而,第二個應用自身也是有疑問的。在特定的情況下,退出問題還是會出現(xiàn)。
第三個示例應用logoutSampleJSP3在第二個示例上進行了改進,比較完善地解決了退出問題。
一個示例logoutSampleStruts展示了Struts如何優(yōu)美地解決登陸問題。
注意:本文所附示例在版本的Microsoft Internet Explorer (IE), Netscape Navigator, Mozilla, FireFox和Avant瀏覽器上測試通過。
Login action
Brian Pontarelli的經(jīng)典文章《J2EE Security: Container Versus Custom》討論了不同的J2EE認證途徑。文章同時指出,HTTP協(xié)議和基于form的認證并未提供處理用戶退出的機制。因此,解決途徑便是引入自定義的安全實現(xiàn)機制。
自定義的安全認證機制普遍采用的方法是從form中獲得用戶輸入的認證信息,然后到諸如LDAP (lightweight directory access protocol)或關系數(shù)據(jù)庫的安全域中進行認證。如果用戶提供的認證信息是有效的,登陸動作往HttpSession對象中注入某個對象。HttpSession存在著注入的對象則表示用戶已經(jīng)登陸。為了方便讀者理解,本文所附的示例只往HttpSession中寫入一個用戶名以表明用戶已經(jīng)登陸。清單1是從loginAction.jsp頁面中節(jié)選的一段代碼以此闡述登陸動作:
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);
//...
本文所附示例均以關系型數(shù)據(jù)庫作為安全域,但本文所闡述的觀點對任何類型的安全域都是適用的。
Logout action
退出動作就包含了簡單的刪除用戶名以及對用戶的HttpSession對象調用invalidate()方法。清單2是從loginoutAction.jsp頁面中節(jié)選的一段代碼以此闡述退出動作:
Listing 2
//...
session.removeAttribute("User");
session.invalidate();
//...
阻止未經(jīng)認證訪問受保護的JSP頁面
從form中獲取用戶提交的認證信息并經(jīng)過驗證后,登陸動作簡單地往 HttpSession對象中寫入一個用戶名,退出動作則做相反的工作,它從用戶的HttpSession對象中刪除用戶名并調用invalidate()方法銷毀HttpSession。為了使登陸和退出動作真正發(fā)揮作用,所有受保護的JSP頁面都應該首先驗證HttpSession中是否包含了用戶名以確認當前用戶是否已經(jīng)登陸。如果HttpSession中包含了用戶名,也就是說用戶已經(jīng)登陸,Web應用則將剩余的JSP頁發(fā)送給瀏覽器,否則,JSP頁將跳轉到登陸頁login.jsp。頁面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
//...
在這個代碼段中,程序從HttpSession中減縮username字符串。如果字符串為空,Web應用則自動中止執(zhí)行當前頁面并跳轉到登陸頁,同時給出Session has ended. Please log in.的提示;如果不為空,Web應用則繼續(xù)執(zhí)行,也就是把剩余的頁面提供給用戶。
運行l(wèi)ogoutSampleJSP1
運行l(wèi)ogoutSampleJSP1將會出現(xiàn)如下幾種情形:
1) 如果用戶沒有登陸,Web應用將會正確中止受保護頁面home.jsp, secure1.jsp, secure2.jsp和logout.jsp的執(zhí)行,也就是說,假如用戶在瀏覽器地址欄中直接敲入受保護JSP頁的地址試圖訪問,Web應用將自動跳轉到登陸頁并提示Session has ended.Please log in.
2) 同樣的,當一個用戶已經(jīng)退出,Web應用也會正確中止受保護頁面home.jsp, secure1.jsp, secure2.jsp和logout.jsp的執(zhí)行
3) 用戶退出后,如果點擊瀏覽器上的后退按鈕,Web應用將不能正確保護受保護的頁面——在Session銷毀后(用戶退出)受保護的JSP頁重新在瀏覽器中顯示出來。然而,如果用戶點擊返回頁面上的任何鏈接,Web應用將會跳轉到登陸頁面并提示Session has ended.Please log in.
阻止瀏覽器緩存
上述問題的根源在于大部分瀏覽器都有一個后退按鈕。當點擊后退按鈕時,默認情況下瀏覽器不是從Web服務器上重新獲取頁面,而是從瀏覽器緩存中載入頁面。基于Java的Web應用并未限制這一功能,在基于PHP、ASP和.NET的Web應用中也同樣存在這一問題。
在用戶點擊后退按鈕后,瀏覽器到服務器再從服務器到瀏覽器這樣通常意思上的HTTP回路并沒有建立,僅僅只是用戶,瀏覽器和緩存進行了交
推薦閱讀
- ·Linux字符設備驅動框架解析:file_operations的核心作用與實現(xiàn)
- ·廣東朝歌數(shù)碼科技股份有限公司專場招聘會
- ·深化產教融合,共筑技能人才培養(yǎng)新生態(tài) —— 廣州華立學院到訪粵嵌從化校區(qū)為深化產教
- ·校企合作新突破 | 粵嵌科技與三亞學院共探產教融合新路徑
- ·粵嵌科技入選國家級職業(yè)數(shù)字展館聯(lián)合建設單位,賦能計算機程序設計員高技能人才培養(yǎng)
- ·嵌入式實時操作系統(tǒng)的性能優(yōu)化與實現(xiàn)路徑
- ·校企攜手賦能教育!粵嵌科技助力海南科技職業(yè)大學探索 AGI 時代教學新范式
- ·嵌入式系統(tǒng)中的低功耗設計策略與實現(xiàn)路徑
- ·深圳市軒宇軟件開發(fā)有限公司專場招聘會
- ·嵌入式系統(tǒng)中的代碼空間優(yōu)化:策略與實踐