通常情況下,瀏覽器會對頁面進行緩存,此時可以通過后退訪問剛才的頁面,如:Web應用登出后后退能夠訪問剛才被緩存的頁面,這樣在有些情況下是不夠安全的,解決防止后退的辦法如下:
response.setHeader("Cache-Control","no-cache"); //不對頁面進行緩存,再次訪問時將從服務器重新獲取最新版本
response.setHeader("Cache-Control","no-store"); //任何情況下都不緩存頁面
response.setDateHeader("Expires", 0); //使緩存過期
response.setHeader("Pragma","no-cache"); //HTTP 1.0 向后兼容
首先要將上面四行代碼加在JSP中,或者Struts的action中,我個人是加在了action里。為一個基於Struts的Web應用添加一個處理退出問題的框架可以優雅地不費氣力的實現。這部分歸功於Struts是采用MVC設計模式的因此將模型和視圖清晰的分開。另外,Java是一個面向對象的語言,其支持繼承,可以比JSP中的腳本更為容易地實現代碼重用。
通過使用類繼承機制,其他類可以繼承基本類BaseAction中的通用邏輯來設置HTTP頭信息以及檢索HttpSession對象中的username字符串。這個基本類是一個抽象類並定義了一個抽象方法executeAction()。所有繼承自基類的子類都應實現exectuteAction()方法而不是覆蓋它。下面基類的部分代碼:
public abstract class BaseAction { ... { response.setHeader("Cache-Control","no-cache"); response.setHeader("Cache-Control","no-store"); response.setDateHeader("Expires", 0); response.setHeader("Pragma","no-cache"); } ... }
登出系統時注意清除保存用戶證書的地方,我是存在了session里。我登出是做了如下操作:
public String logout() { ActionContext context = ActionContext.getContext(); Map session = context.getSession(); session.remove("User");//User中有用戶名和密碼等信息 //ActionContext.getContext().getSession().clear();//清空session //ServletActionContext.getRequest().getSession().invalidate();//使HttpSession失效 return "logout"; }
另外要配置一個攔截器,來保證已登出的用戶不能后退進系統:
public class LoginSessionFilter implements javax.servlet.Filter { @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req=(HttpServletRequest)request; HttpServletResponse res=(HttpServletResponse)response; String contextPath = req.getSession().getServletContext().getContextPath(); String servletPath = req.getServletPath(); User user = (User) req.getSession().getAttribute("User "); // 如果是登錄首頁不用攔截 if (servletPath.contains("login.action")) { chain.doFilter(request, response); } else { // 如果user == null說明該用戶已經登出了,我強制它返回登錄頁面 // 否則不攔截 if (user == null) { res.sendRedirect(contextPath + " login.action"); } else { chain.doFilter(request, response); } } } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } }
當做到上面編碼之后,已經可以解決99%的問題了,不過當瀏覽器點后退對應的是登錄后的action時,由於這個action做了用戶名密碼的認證,后退鍵將用戶名密碼又提交了回來,因此還會登錄進系統,攔截后退便失敗。於是,我們可以做一個時間來驗證一下這個請求是否是正常的登錄請求:
public class LoginAction extends BaseAction { private String userName; // 用戶名 private String password; // 密碼 private long logonTime;// 登陸時間 private static long lastLogonTime ; // 上次登錄時間 public String logon() { // 如果本次登錄的時間大於最后一次登錄的時間,說明是正常登錄 // 否則說明該請求是瀏覽器緩存的歷史,我們要跳回登錄頁面 if (logonTime > lastLogonTime) { lastLogonTime = logonTime; } else { return "登錄頁面"; } ... ... return ""; } }
結論
本文闡述了解決退出問題的方案,盡管方案簡單的令人驚訝,但卻在所有情況下都能有效地工作。無論是對JSP還是Struts,所要做的不過是寫一段不超過50行的代碼以及一個記錄用戶最后登陸時間的方法。在Web應用中混合使用這些方案能夠使擁護的私人數據不致泄露,同時,也能增加用戶的經驗
