Java Web Application使Session永不失效(利用cookie隱藏登錄)


  在做 Web Application 時,因為 Web Project 有 session 自動失效的問題,所以如何讓用戶登錄一次系統就能長時間運行三個月,就是個問題。

  后來,看到 session 失效的攔截器代碼,就猜想能否通過攔截器來實現。

  查資料發現可行:用戶登錄時將帳號密碼存入cookie,cookie可以存儲1年至更久,當session失效被攔截時,在攔截器內讀取cookie 中的用戶名和密碼后再登錄。(登錄過程隱藏對用戶不可見)。

  在實踐過程中遇到個問題: 在攔截器內重新實現登錄過程(包括寫session),此時寫session是成功的,但是返回被攔截器攔截的 Action 方法內時,Action 內的方法讀取的session卻是空的。(2017-06-12 更新,出錯原因是保存的sesion和讀取的session分別是Strut2包裝的session和JSP/Sevlert內置的session,導致讀取為空,參見)

 


 方法一:設置 session-timeout 參數值

 

最簡單的辦法是,在Java Web 中可通過設置 web.xml 中的 session-timeout 為 -1 即可實現 session 永不失效。

Java Web中有關 Session 失效的設置有三處:

1. 頁面或者代碼內通過 session.setMaxInactiveInterval

2. 項目的web.xml 中的 session-timeout (驗證有效)

3. Tomcat 的 server.xml 中的  (該方法本文未驗證,網上搜集)

<Context path="/livsorder" docBase="/home/httpd/html/livsorder" 
  defaultSessionTimeOut="3600" isWARExpanded="true" 
  isWARValidated="false" isInvokerEnabled="true" 
  isWorkDirPersistent="false"/> 

4. Tomcat 的 web.xml 中的 (該方法本文未驗證,網上搜集)

<session-config>  
        <session-timeout>30</session-timeout>  
</session-config>  

 

分別對應:

1. 當前會話生效

2. 整個Web應用有效

3. 不詳

4. 不詳

 

設置產生效果的優先順序很顯然是:1 -> 2 ,沒有指明就是用默認設置。

 

另外: setMaxInactiveInterval的參數是秒,session-config當中配置的session-timeout是分鍾。  設置session-timeout是永久有效。【setMaxInactiveInterval(-1)也是元永久有效(本人未測試)】。測試是否是永久有效很簡單,只需要在本地測試(localhost)時,將本機的時間調整為幾個月之后即可。

 

但在實際使用中並不理想,因為超出 tomcat 的默認是 30 分鍾,如果修改 tomcat 默認值,會影響其他項目不說,也很容易遺忘,對今后產生莫名其妙的問題。

 


 

方法二:使用 Struts2 攔截器

  原理:在使用了 Struts 框架的代碼中,使用攔截器,測試Session 是否為空,若是空,利用 cookie 里藏的用戶名和密碼進行登錄,並保存到 session 中。

代碼:(本人親測,實際使用)

1. 登錄保存到 Struts2 包裝的 session中(注意,前后session要對應)

 根據項目需要,可決定是否加密。我示例未加密。

 

// 你的登錄方法內部
// user 是登錄成功后的用戶對象
ActionContext.getContext().getSession().put("user", user);

//創建或覆蓋COOKIE
Cookie ckName = new Cookie("jsjgUserName", username);
Cookie ckPwd = new Cookie("jsjgUserPwd", password);
ckName.setMaxAge(365*24*60*60);
ckPwd.setMaxAge(365*24*60*60);
response.addCookie(ckName);
response.addCookie(ckPwd);

 

 

 

2. 攔截器代碼

package com.tools;


import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;

import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsStatics;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
import com.zhzx.class_entity.User;
import com.zhzx.service.UserService;

@SuppressWarnings("serial")
public class MyInterceptor implements Interceptor {
    


    public void destroy() {
    }

    public void init() {
    }

    public String intercept(ActionInvocation actionInvocation) throws Exception {

        // 確認Session是否過期
        Map strutSession = actionInvocation.getInvocationContext().getSession();
        Cookie[] cookies = ServletActionContext.getRequest().getCookies();
        
        User us=(User) strutSession.get("user");
        String userName = "";
        String userPwd = "";
        
        if (us!=null&&!"".equals(us)) {
            return actionInvocation.invoke();
        } else {
            //從cookie得到登錄賬戶
            if(cookies != null){
                for(Cookie cookie:cookies){
                    if(cookie.getName().equalsIgnoreCase("jsjgUserName")){
                        userName = cookie.getValue();
                        System.out.println(userName);
                    }else if(cookie.getName().equalsIgnoreCase("jsjgUserPwd")){
                        userPwd = cookie.getValue();
                    }
                }
                //登錄
                if(userName != null && userPwd != null){
                    
                    //因項目使用了SSH,所以這里是獲取Spring管理的bean
                    ServletContext context = (ServletContext) actionInvocation.getInvocationContext().get(StrutsStatics.SERVLET_CONTEXT); 
                    ApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(context);
                    UserService userService = (UserService)ctx.getBean("UserService");
                    
                    //是否注入成功
                    System.out.println(userService);
                    
                    //登錄並放入Strtu2包裝的session
                    User user=userService.Login(userName);
                    if(user != null && user.getPassword().toLowerCase().equals(userPwd.toLowerCase())){
                        strutSession.put("user", user);
                    }
                    
                    return actionInvocation.invoke();
                }
                
                
            }
            return "timeout";
        }
    }


}

然后攔截器按照常規方法使用即可。攔截器可以看看 Struts in Action ,Struts實戰之類的書及PDF,有詳細的講解和例子。

 

 

吐槽:Java是太龐雜了,框架多不說,使用起來也方法各樣,一會兒流行配置文件,一會兒流行注解,一會SSH,一會SSM,一會Sping MVC。

我就想說這不都是自己折騰自己么,學習成本不是成本么,發明出這么多輪子,軟件行業不還是加班。舊的軟件項目不還是要維護。

Java體系真是自己折騰自己,真心無愛了。 

我覺得框架只是工具,就像武俠世界里,真正的高手是用什么工具都可以殺人於無形,那管你是用很多人鄙視的 ASP.NET 還是自以為很牛逼的Java Web,

甲方和老板關心的無非是你做完了么,做的好看么,是不是?

程序員,工程師們還是消停點好,多關心下自己的健康和身邊的人不好么?

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM