您好,登錄后才能下訂單哦!
這篇文章給大家介紹spring-session中怎么動(dòng)態(tài)修改cookie的max-age,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。
使用spring-session時(shí),動(dòng)態(tài)修改cookie的max-age
不論是使用spring提供的spring-session
,還是使用servle容器實(shí)現(xiàn)的http session
。原理都是把session-id
以cookie
的形式存儲(chǔ)在客戶(hù)端。每次請(qǐng)求都帶上cookie
。服務(wù)器通過(guò)session-id
,找到session
。
https://springboot.io/t/topic/864
用戶(hù)登錄的時(shí)候,通常需要一個(gè)【記住我】的選擇框,表示是否要長(zhǎng)期的保持會(huì)話(huà)。
【記住我】× 一般會(huì)把cookie的max-age
設(shè)置為 -1,表示在瀏覽器關(guān)閉的時(shí)候,就自動(dòng)的刪除cookie。對(duì)于客戶(hù)端而言關(guān)閉了瀏覽器,就是丟失了會(huì)話(huà),需要重新的登錄系統(tǒng)。特別在公共場(chǎng)合登陸了某些系統(tǒng)后,忘記執(zhí)行‘退出’操作,直接關(guān)閉了瀏覽器,后面使用電腦的人打開(kāi)瀏覽器,也必須先登錄才可以訪(fǎng)問(wèn)系統(tǒng)。這樣在一定的程度上保證了安全性。
【記住我】√ 一般在自己私人電腦上選擇,目的是為了避免重復(fù)的登錄操作。登錄成功,一般會(huì)把max-age
的值設(shè)置為比較長(zhǎng),就算是關(guān)閉了瀏覽器。重新打開(kāi),也不需要再次執(zhí)行登錄操作。
使用spring-session
時(shí),可以通過(guò)yml配置,或者代碼配置的形式來(lái)設(shè)置max-age
的屬性。但是問(wèn)題在于所有的session創(chuàng)建,都是使用同樣的屬性。在【記住我】這個(gè)功能上會(huì)出現(xiàn)一些問(wèn)題
固定設(shè)置:max-age=-1,那么就算是勾選了【記住我】,也會(huì)因?yàn)闉g覽器關(guān)閉刪除cookie,而丟失會(huì)話(huà)。下次打開(kāi)瀏覽器還是需要重新執(zhí)行登錄
固定設(shè)置: max-age=604800(7天),那么用戶(hù)在未勾選【記住我】的情況下,關(guān)閉瀏覽器。cookie并不會(huì)被立即刪除,任何人再次打開(kāi)這個(gè)系統(tǒng)。都不需要登錄就可以直接操作系統(tǒng)。
總的來(lái)說(shuō)就是,固定的max-age
屬性,會(huì)導(dǎo)致【記住我】功能失效。
spring-session 通過(guò)接口 CookieSerializer,來(lái)完成對(duì)客戶(hù)端cookie的讀寫(xiě)操作。并且提供了一個(gè)默認(rèn)的實(shí)現(xiàn)類(lèi): DefaultCookieSerializer。我們想要?jiǎng)討B(tài)的修改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 設(shè)置了maxAge屬性,則該屬性?xún)?yōu)先 } } return cookieValue.getCookieMaxAge(); // cookieValue 默認(rèn)的maxAge屬性 = -1 }
可以看出,spring-session并沒(méi)使用servlet提供的cookie api來(lái)響應(yīng)cookie。而是自己構(gòu)造Cookie頭。而且還提供了Servlet還未實(shí)現(xiàn)的,Cookie的新屬性:sameSite,可以用來(lái)防止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 { // 如果未設(shè)置,就使用默認(rèn)cookie的生命周期 cookieValue.setCookieMaxAge(this.cookieMaxAge); } if (LOGGER.isDebugEnabled()) { LOGGER.debug("動(dòng)態(tài)設(shè)置cooke.max-age={}", cookieValue.getCookieMaxAge()); } super.writeCookieValue(cookieValue); } }
原理就是,把cookie的maxAge屬性存儲(chǔ)到request域。在響應(yīng)客戶(hù)端之前,動(dòng)態(tài)的設(shè)置。
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) { // 不記住我 // 設(shè)置cookie的生命周期為 -1 request.setAttribute(DynamicCookieMaxAgeCookieSerializer.COOKIE_MAX_AGE, -1); // 設(shè)置session僅緩存30分鐘 httpSession.setMaxInactiveInterval(60 * 30); } ModelAndView modelAndView = new ModelAndView("test/test"); return modelAndView; } }
http://localhost/test/session?remember=true
響應(yīng)Cookie,存儲(chǔ)時(shí)間是 7 天
redis的session存儲(chǔ),緩存時(shí)間是7天
http://localhost/test/session?remember=false
響應(yīng)Cookie,存儲(chǔ)時(shí)間是:-1,臨時(shí)會(huì)話(huà)設(shè)置成功,瀏覽器關(guān)閉Cookie刪除
redis的session存儲(chǔ),緩存時(shí)間是30分鐘,超過(guò)30分鐘不活動(dòng),自動(dòng)刪除
關(guān)于spring-session中怎么動(dòng)態(tài)修改cookie的max-age就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。