Springboot2.x的session和cookie有效期
session和cookie的相關區別和聯系就不介紹了,這里就記錄一下筆記。
背景
最近在做單點登錄CAS的問題,在后端塞一個cookie uid用于前端的登錄拉起,并且設置了max-age, 但是測試的時候,一直有個問題,就是前端頁面打開,不做任何操作,停留30分鐘左右,然后點擊按鈕,按理說是應該會發送到后端,但是實際上卻發生了302的跳轉,前端也沒有拉起登錄頁面,說明登錄狀態還在(根據uid判斷),但是為什么后端日志沒有打印??
也就是說,頁面半小時左右沒做任何操作,這個按鈕就跳出了前端和后端,失去了控制,百思不得其解啊。
經過一番排查,終于發現問題了,前端的登錄態判斷條件,uid是后端塞進去的,并且設置了max-age為1小時,但是項目里的springboot2.x,并沒有配置下面內容:
server.servlet.session.timeout= # session的有效期,默認為30min server.servlet.session.cookie.max-age= #cookie的有效期,默認為-1 即是和瀏覽器關閉狀態有關
后來測試了一番,在代碼里add cookie和 server.servlet.session.cookie.max-age 之間的參數比較
public int test(HttpServletRequest request, HttpServletResponse response) { int maxInactiveInterval = request.getSession().getMaxInactiveInterval(); Cookie[] cookies = request.getCookies(); System.out.println("maxInactiveInterval: " + maxInactiveInterval); Cookie cookie = new Cookie("uid","koo"); cookie.setMaxAge(5); response.addCookie(cookie); return maxInactiveInterval; }
測試策略為:
設置server.servlet.session.cookie.max-age 和 cookie.setMaxAge(5);的值不一樣,然后在瀏覽器查看。
最后的結論是:
server.servlet.session.cookie.max-age控制的是JESSIONID的有效期,Cookie cookie = new Cookie(“uid”,“koo”); cookie.setMaxAge(5);這種方式的cookie 特定字段的有效期是分開的。
另外一個配置:
server.servlet.session.timeout表示的是session的有效期,查看源代碼默認值為:30min,或者也可以這樣輸出session的有效期:int maxInactiveInterval = request.getSession().getMaxInactiveInterval();
項目問題解釋
我在項目里只有Cookie cookie = new Cookie(“uid”,“koo”); cookie.setMaxAge(3600); 并且是設置為3600秒的有效期,但是服務器的session有效期server.servlet.session.timeout是沒有配置的,所以前端登錄態判斷的時候,uid是還存在的,所以發送請求的時候,不會拉起登錄頁面,會把請求發送出去,但是后端的session已經過期了,導致發生302的請求,請求看起來失去了控制。
最后解決辦法為
server.servlet.session.timeout=86400 server.servlet.session.cookie.max-age=86400 Cookie cookie = new Cookie(“uid”,“koo”); cookie.setMaxAge(23*3600); response.addCookie(cookie);
登錄態字段的cookie有效期要小于session的有效期,這樣就會在先于發送請求的時候,拉起登錄頁面了,不會再出現失去控制的情況。
升級springboot 2.x 踩過的坑――跨域導致session問題
目前IT界主流前后端分離,但是在分離過程中一定會存在跨域的問題。
什么是跨域?
是指瀏覽器從一個域名的網頁去請求另一個域名的資源時,域名、端口、協議任一不同,都是跨域。
做過web后臺的童鞋都知道,跨域這種問題是比較常見的,最近我們公司需要將springboot 1.x升級到2.x,在升級之后遇到了挺多的問題,例如某些類過時了或者某些類找不到等,還有就是今天要說得session不一致的情況(eg:請求不同接口,sessionID都不一致,即session不會共享)。
場景
今天前端童鞋跟我說,本地環境調用校驗驗證碼接口一直報“未獲取到用戶信息,請重新登錄”,我直接看了下這個接口,他是從session中獲取的用戶信息,如果用戶不存在則會拋這種提示語。
HttpSession session = request.getSession(false); Object sessionObj = session.getAttribute(LOGIN_NAME);//session為空 String currentName = null == sessionObj ? null : sessionObj.toString(); if (StringUtils.isBlank(currentName)) { res.setMessage(messageUtil.getMessage("reLogin")); res.setStatusCode(StatusCode.RE_LOGIN.getCode()); return res; }
因為我們登錄和校驗驗證碼是兩個接口,所以用戶信息是從登錄放進去的,然后在驗證碼接口中獲取用戶信息做后面的進一步操作。
看到這個之后,我看了下springboot的配置,都有配置session 共享的配置,而且我的session是放在redis里面的,有點郁悶,然后我就登錄到測試環境登錄一下試試看,咦~~居然可以,最后才反應過來是跨域的問題,然后我又去看了下代碼,是有配置跨域的問題,真奇怪!
經過一天的百度與排查,我回滾到springboot 1.x居然沒有這個問題,才定位到是升級到springboot 2.x導致的原因,好了,已經抓住兇手了,這下子好對癥下藥了,去網上看了 springboot升級到2.xspring session 相關的問題。
終于發現了新大陸,spring-session 2.x 中 Cookie里面居然引入了SameSite 這個叼毛,他默認值是 Lax,好了咱們來看看這個是什么東西?
SameSite Cookie 是用來防止CSRF攻擊,它有兩個值:Strict、Lax
- SameSite = Strict:
意為嚴格模式,表明這個cookie在任何情況下都不可能作為第三方cookie;
- SameSite = Lax:
意為寬松模式,在get請求是可以作為第三方cookie,但是不能攜帶cookie進行跨域post訪問(這就很蛋疼了,我們那個校驗接口就是POST請求)
總結
前端請求到后臺,每次session都不一樣,每次都是新的會話,導致獲取不到用戶信息
解決方案
將SameSite設置為空
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.session.web.http.CookieSerializer; import org.springframework.session.web.http.DefaultCookieSerializer; @Configuration public class SpringSessionConfig { public SpringSessionConfig() { } @Bean public CookieSerializer httpSessionIdResolver() { DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer(); // 取消僅限同一站點設置 cookieSerializer.setSameSite(null); return cookieSerializer; } }
pom.xml依賴
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-core</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session</artifactId> <version>1.3.1.RELEASE</version> </dependency>
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/Agly_Clarlie/article/details/90050740