溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

spring-session中怎么動(dòng)態(tài)修改cookie的max-age

發(fā)布時(shí)間:2021-08-03 11:25:13 來(lái)源:億速云 閱讀:380 作者:Leah 欄目:大數(shù)據(jù)

這篇文章給大家介紹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-idcookie的形式存儲(chǔ)在客戶(hù)端。每次請(qǐng)求都帶上cookie服務(wù)器通過(guò)session-id,找到session。

spring-session的使用

https://springboot.io/t/topic/864

由“記住我”引發(fā)的一個(gè)問(wèn)題

用戶(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 配置cookie的max-age屬性

使用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時(shí)的解決方案

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攻擊。

覆寫(xiě) DefaultCookieSerializer

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è)置。

添加到IOC

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屬性。

測(cè)試接口

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 天

spring-session中怎么動(dòng)態(tài)修改cookie的max-age

redis的session存儲(chǔ),緩存時(shí)間是7天 spring-session中怎么動(dòng)態(tài)修改cookie的max-age

【記住我】×

http://localhost/test/session?remember=false

響應(yīng)Cookie,存儲(chǔ)時(shí)間是:-1,臨時(shí)會(huì)話(huà)設(shè)置成功,瀏覽器關(guān)閉Cookie刪除

spring-session中怎么動(dòng)態(tài)修改cookie的max-age

redis的session存儲(chǔ),緩存時(shí)間是30分鐘,超過(guò)30分鐘不活動(dòng),自動(dòng)刪除

spring-session中怎么動(dòng)態(tài)修改cookie的max-age

關(guān)于spring-session中怎么動(dòng)態(tài)修改cookie的max-age就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(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)容。

AI