您好,登錄后才能下訂單哦!
這篇文章給大家介紹spring-session中怎么動態修改cookie的max-age,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
使用spring-session時,動態修改cookie的max-age
不論是使用spring提供的spring-session
,還是使用servle容器實現的http session
。原理都是把session-id
以cookie
的形式存儲在客戶端。每次請求都帶上cookie
。服務器通過session-id
,找到session
。
https://springboot.io/t/topic/864
用戶登錄的時候,通常需要一個【記住我】的選擇框,表示是否要長期的保持會話。
【記住我】× 一般會把cookie的max-age
設置為 -1,表示在瀏覽器關閉的時候,就自動的刪除cookie。對于客戶端而言關閉了瀏覽器,就是丟失了會話,需要重新的登錄系統。特別在公共場合登陸了某些系統后,忘記執行‘退出’操作,直接關閉了瀏覽器,后面使用電腦的人打開瀏覽器,也必須先登錄才可以訪問系統。這樣在一定的程度上保證了安全性。
【記住我】√ 一般在自己私人電腦上選擇,目的是為了避免重復的登錄操作。登錄成功,一般會把max-age
的值設置為比較長,就算是關閉了瀏覽器。重新打開,也不需要再次執行登錄操作。
使用spring-session
時,可以通過yml配置,或者代碼配置的形式來設置max-age
的屬性。但是問題在于所有的session創建,都是使用同樣的屬性。在【記住我】這個功能上會出現一些問題
固定設置:max-age=-1,那么就算是勾選了【記住我】,也會因為瀏覽器關閉刪除cookie,而丟失會話。下次打開瀏覽器還是需要重新執行登錄
固定設置: max-age=604800(7天),那么用戶在未勾選【記住我】的情況下,關閉瀏覽器。cookie并不會被立即刪除,任何人再次打開這個系統。都不需要登錄就可以直接操作系統。
總的來說就是,固定的max-age
屬性,會導致【記住我】功能失效。
spring-session 通過接口 CookieSerializer,來完成對客戶端cookie的讀寫操作。并且提供了一個默認的實現類: DefaultCookieSerializer。我們想要動態的修改cookie的max-age屬性,核心方法在于。
@Override public void writeCookieValue(CookieValue cookieValue) { ... StringBuilder sb = new StringBuilder(); sb.append(this.cookieName).append('='); ... int maxAge = getMaxAge(cookieValue); // 讀取maxAge屬性 if (maxAge > -1) { sb.append("; Max-Age=").append(cookieValue.getCookieMaxAge()); ZonedDateTime expires = (maxAge != 0) ? ZonedDateTime.now(this.clock).plusSeconds(maxAge) : Instant.EPOCH.atZone(ZoneOffset.UTC); sb.append("; Expires=").append(expires.format(DateTimeFormatter.RFC_1123_DATE_TIME)); } ... } private int getMaxAge(CookieValue cookieValue) { int maxAge = cookieValue.getCookieMaxAge(); if (maxAge < 0) { if (this.rememberMeRequestAttribute != null && cookieValue.getRequest().getAttribute(this.rememberMeRequestAttribute) != null) { cookieValue.setCookieMaxAge(Integer.MAX_VALUE); } else if (this.cookieMaxAge != null) { cookieValue.setCookieMaxAge(this.cookieMaxAge); // 如果 DefaultCookieSerializer 設置了maxAge屬性,則該屬性優先 } } return cookieValue.getCookieMaxAge(); // cookieValue 默認的maxAge屬性 = -1 }
可以看出,spring-session并沒使用servlet提供的cookie api來響應cookie。而是自己構造Cookie頭。而且還提供了Servlet還未實現的,Cookie的新屬性:sameSite,可以用來防止csrf攻擊。
import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.session.web.http.DefaultCookieSerializer; // @Component public class DynamicCookieMaxAgeCookieSerializer extends DefaultCookieSerializer { private static final Logger LOGGER = LoggerFactory.getLogger(DynamicCookieMaxAgeCookieSerializer.class); public static final String COOKIE_MAX_AGE = "cookie.max-age"; @Value("${server.servlet.session.cookie.max-age}") private Integer cookieMaxAge; @Override public void writeCookieValue(CookieValue cookieValue) { HttpServletRequest request = cookieValue.getRequest(); // 從request域讀取到cookie的maxAge屬性 Object attribute = request.getAttribute(COOKIE_MAX_AGE); if (attribute != null) { cookieValue.setCookieMaxAge((int) attribute); } else { // 如果未設置,就使用默認cookie的生命周期 cookieValue.setCookieMaxAge(this.cookieMaxAge); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("動態設置cooke.max-age={}", cookieValue.getCookieMaxAge()); } super.writeCookieValue(cookieValue); } }
原理就是,把cookie的maxAge屬性存儲到request域。在響應客戶端之前,動態的設置。
import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.session.web.http.CookieSerializer; import com.video.manager.spring.session.DynamicCookieMaxAgeCookieSerializer; @Configuration public class SpringSessionConfiguration { @Value("${server.servlet.session.cookie.name}") private String cookieName; @Value("${server.servlet.session.cookie.secure}") private Boolean cookieSecure; // @Value("${server.servlet.session.cookie.max-age}") // private Integer cookieMaxAge; @Value("${server.servlet.session.cookie.http-only}") private Boolean cookieHttpOnly; @Value("${server.servlet.session.cookie.same-site}") private String cookieSameSite; @Bean public CookieSerializer cookieSerializer() { DynamicCookieMaxAgeCookieSerializer serializer = new DynamicCookieMaxAgeCookieSerializer(); serializer.setCookieName(this.cookieName); // serializer.setCookieMaxAge(this.cookieMaxAge); serializer.setSameSite(this.cookieSameSite); serializer.setUseHttpOnlyCookie(this.cookieHttpOnly); serializer.setUseSecureCookie(this.cookieSecure); return serializer; } }
使用 @Value,讀取yml配置中的Cookie屬性。
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import com.video.manager.spring.session.DynamicCookieMaxAgeCookieSerializer; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; @Controller @RequestMapping("/test") public class TestController { static final Logger LOGGER = LoggerFactory.getLogger(TestController.class); @GetMapping("/session") public ModelAndView session(HttpServletRequest request, @RequestParam("remember")Boolean remember) { HttpSession httpSession = request.getSession(); LOGGER.debug("httpSession={}", httpSession); if (!remember) { // 不記住我 // 設置cookie的生命周期為 -1 request.setAttribute(DynamicCookieMaxAgeCookieSerializer.COOKIE_MAX_AGE, -1); // 設置session僅緩存30分鐘 httpSession.setMaxInactiveInterval(60 * 30); } ModelAndView modelAndView = new ModelAndView("test/test"); return modelAndView; } }
http://localhost/test/session?remember=true
響應Cookie,存儲時間是 7 天
redis的session存儲,緩存時間是7天
http://localhost/test/session?remember=false
響應Cookie,存儲時間是:-1,臨時會話設置成功,瀏覽器關閉Cookie刪除
redis的session存儲,緩存時間是30分鐘,超過30分鐘不活動,自動刪除
關于spring-session中怎么動態修改cookie的max-age就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。