SpringSession Series — Разрешение SessionId и стратегия чтения и записи файлов cookie

Spring

Прежде всего, здесь объясняются требования. Процесс итерации версии SpringSession определенно будет сопровождаться удалением некоторых классов и добавлением некоторых классов. Версия, используемая в настоящее время в этой серии, представляет собой версию потока кода мастера объект на гитхабе. Если есть студенты, у которых есть сомнения по поводу некоторых классов или обработки в других версиях, милости просим к общению.

Эта статья познакомитSpringSessionсредние дваsessionIdСтратегия синтаксического анализа, которая фактически упоминалась в предыдущей статье, будет вынесена и обсуждена здесь.SpringSessionсерединаCookieУзнайте о соответствующих стратегиях Вниз.

Стратегия разрешения sessionId

SpringSessionсреда дляsessionIdСтратегия, связанная с синтаксическим анализом, проходит черезHttpSessionIdResolverЭтот интерфейс отражен.HttpSessionIdResolverЕсть два класса реализации:

在这里插入图片描述

Эти два класса соответствуютSpringSessionРазобратьsessionIdдве разные стратегии реализации. Прежде чем углубляться в детали реализации различных стратегий, давайте взглянемHttpSessionIdResolverКаковы некоторые из поведений, определяемых интерфейсом.

HttpSessionIdResolver

HttpSessionIdResolverОпределенныйsessionIdКонтракт на парсинг стратегии (Contract). Позволяет разрешить sessionId с запросом и отправить sessionId с ответом или завершить сеанс. Интерфейс определяется следующим образом:

public interface HttpSessionIdResolver {
	List<String> resolveSessionIds(HttpServletRequest request);
	void setSessionId(HttpServletRequest request, HttpServletResponse response,String sessionId);
	void expireSession(HttpServletRequest request, HttpServletResponse response);
}

HttpSessionIdResolverЕсть три метода:

  • resolveSessionIds: разрешает текущий запрос, связанный сsessionId.sessionIdможет исходить отCookieили заголовки запроса.
  • setSessionId: будет ли данныйsessionIdотправлено клиенту. Этот метод создает новыйsessionвызывается и информирует клиента о новомsessionIdчто.
  • expireSession: Указывает клиенту завершить текущийsession. когдаsessionЭтот метод вызывается, когда он недействителен, и должен уведомить клиента.sessionIdБолее не действителен. Например, он может удалитьsessionIdизCookie, или установитеHTTPЗаголовок ответа, значение которого пусто, означает, что клиент больше не будет отправлятьsessionId.

Ниже приводится подробный анализ двух упомянутых выше стратегий.

Анализировать sessionId на основе cookie

Класс реализации, соответствующий этой стратегии, равенCookieHttpSessionIdResolver, начиная сCookieполучено вsession; в частности, эта реализация позволит использоватьCookieHttpSessionIdResolver#setCookieSerializer(CookieSerializer)уточнитьCookieСтратегия сериализации. дефолтCookieимя это "SESSION".Создаватьsessionчас,HTTPОтвет будет содержать указанныйCookie nameа такжеvalueдаsessionIdизCookie.Cookieбудет отмечен какsession cookie,Cookieизdomain pathиспользоватьcontext path, и отмечен какHttpOnly,еслиHttpServletRequest#isSecure()вернутьtrue,ТакCookieбудет помечен как безопасный. следующее:

оCookie, вы можете обратиться к:Поговорим о сеансах и файлах cookie.

HTTP/1.1 200 OK
Set-Cookie: SESSION=f81d4fae-7dec-11d0-a765-00a0c91e6bf6; Path=/context-root; Secure; HttpOnly

В это время клиент должен указать тот жеCookieвключатьsessionИнформация. Например:

 GET /messages/ HTTP/1.1
 Host: example.com
 Cookie: SESSION=f81d4fae-7dec-11d0-a765-00a0c91e6bf6

Когда сеанс недействителен, сервер отправит просроченныйHTTPоткликCookie,Например:

 HTTP/1.1 200 OK
 Set-Cookie: SESSION=f81d4fae-7dec-11d0-a765-00a0c91e6bf6; Expires=Thur, 1 Jan 1970 00:00:00 GMT; Secure; HttpOnly

CookieHttpSessionIdResolverРеализация класса выглядит следующим образом:

public final class CookieHttpSessionIdResolver implements HttpSessionIdResolver {
	private static final String WRITTEN_SESSION_ID_ATTR = CookieHttpSessionIdResolver.class
			.getName().concat(".WRITTEN_SESSION_ID_ATTR");
	// Cookie序列化策略,默认是 DefaultCookieSerializer
	private CookieSerializer cookieSerializer = new DefaultCookieSerializer();

	@Override
	public List<String> resolveSessionIds(HttpServletRequest request) {
		// 根据提供的cookieSerializer从请求中获取sessionId
		return this.cookieSerializer.readCookieValues(request);
	}

	@Override
	public void setSessionId(HttpServletRequest request, HttpServletResponse response,
			String sessionId) {
		if (sessionId.equals(request.getAttribute(WRITTEN_SESSION_ID_ATTR))) {
			return;
		}
		request.setAttribute(WRITTEN_SESSION_ID_ATTR, sessionId);
		// 根据提供的cookieSerializer将sessionId回写到cookie中
		this.cookieSerializer
				.writeCookieValue(new CookieValue(request, response, sessionId));
	}

	@Override
	public void expireSession(HttpServletRequest request, HttpServletResponse response) {
		// 这里因为是过期,所以回写的sessionId的值是“”,当请求下次进来时,就会取不到sessionId,也就意味着当前会话失效了
		this.cookieSerializer.writeCookieValue(new CookieValue(request, response, ""));
	}
  
   // 指定Cookie序列化的方式
	public void setCookieSerializer(CookieSerializer cookieSerializer) {
		if (cookieSerializer == null) {
			throw new IllegalArgumentException("cookieSerializer cannot be null");
		}
		this.cookieSerializer = cookieSerializer;
	}
}

можно увидеть здесьCookieHttpSessionIdResolverОперации чтения вCookieSerializerзавершить.CookieSerializerдаSpringSessionсреда дляCookieМеханизм, обеспечиваемый операциями. Подробности ниже.

Анализировать sessionId на основе заголовка запроса

Класс реализации, соответствующий этой стратегии, равенHeaderHttpSessionIdResolver, запросив заголовки изheaderразобранsessionId. В частности, эта реализация позволит использоватьHeaderHttpSessionIdResolver(String)чтобы указать имя заголовка. Удобные фабричные методы также можно использовать для создания имен заголовков с использованием общедоступных заголовков (например,“X-Auth-Token”а также“authenticing-info”) пример. При создании сеансаHTTPОтвет будет иметь указанное имя иsessionIdзначение заголовка ответа.

// 使用X-Auth-Token作为headerName
public static HeaderHttpSessionIdResolver xAuthToken() {
	return new HeaderHttpSessionIdResolver(HEADER_X_AUTH_TOKEN);
}
// 使用Authentication-Info作为headerName
public static HeaderHttpSessionIdResolver authenticationInfo() {
	return new HeaderHttpSessionIdResolver(HEADER_AUTHENTICATION_INFO);
}

HeaderHttpSessionIdResolverобработкаsessionIdв сравнении сCookieHttpSessionIdResolverЭто намного проще. вокругrequest.getHeader(String)а такжеrequest.setHeader(String,String)Есть два способа играть.

HeaderHttpSessionIdResolverЭта стратегия обычно используется на стороне беспроводной связи, чтобы компенсироватьCookieподдержка сцены.

Стратегия сериализации файлов cookie

на основеCookieРазобратьsessionIdкласс реализацииCookieHttpSessionIdResolverактуально дляCookieОперации чтения и записи выполняются черезCookieSerializerзавершить.SpringSessionпри условииCookieSerializerРеализация интерфейса по умолчаниюDefaultCookieSerializer, конечно, в практических приложениях мы тоже можем сами реализовать этот интерфейс, а потом передатьCookieHttpSessionIdResolver#setCookieSerializer(CookieSerializer)метод, чтобы указать нашу собственную реализацию.

PS: Надо сказать, что мощная возможность расширения пользователя действительноSpringОтличный семейный стиль.

Из-за ограниченного места здесь всего два пункта:

CookieValue

CookieValueдаCookieSerializerВнутренний класс в , который инкапсулируетHttpServletResponseНапишите всю необходимую информацию. фактическиCookieValueНет особого смысла в существованииCookieValueинкапсуляция для упрощения обратной записиcookieПроблема с передачей параметров по ссылке, но нагрузки это не снижает.

Обратная запись файлов cookie

CookieНапишите ответ я думаю для распределенногоsessionимеет важное значение для реализацииservletосуществленныйHttpSession, нам на самом деле не нужно заботиться об обратной записи, когда мы ее используемcookieэто дело, потому чтоservletКонтейнеры все готовы. Но для распределенногоsessionНапример, после перезаписиresponse, так что вам нужно вернутьсяresponseнеобходимо преобразовать текущийsessionинформация черезcookieспособ подключитьresponseвозвращается клиенту - этоCookieОбратная запись. НижеDefaultCookieSerializerнаписать ответCookieЛогика, детали отмечены в коде комментариями.

@Override
public void writeCookieValue(CookieValue cookieValue) {
	HttpServletRequest request = cookieValue.getRequest();
	HttpServletResponse response = cookieValue.getResponse();
	StringBuilder sb = new StringBuilder();
	sb.append(this.cookieName).append('=');
	String value = getValue(cookieValue);
	if (value != null && value.length() > 0) {
		validateValue(value);
		sb.append(value);
	}
	int maxAge = getMaxAge(cookieValue);
	if (maxAge > -1) {
		sb.append("; Max-Age=").append(cookieValue.getCookieMaxAge());
		OffsetDateTime expires = (maxAge != 0)
				? OffsetDateTime.now().plusSeconds(maxAge)
				: Instant.EPOCH.atOffset(ZoneOffset.UTC);
		sb.append("; Expires=")
				.append(expires.format(DateTimeFormatter.RFC_1123_DATE_TIME));
	}
	String domain = getDomainName(request);
	if (domain != null && domain.length() > 0) {
		validateDomain(domain);
		sb.append("; Domain=").append(domain);
	}
	String path = getCookiePath(request);
	if (path != null && path.length() > 0) {
		validatePath(path);
		sb.append("; Path=").append(path);
	}
	if (isSecureCookie(request)) {
		sb.append("; Secure");
	}
	if (this.useHttpOnlyCookie) {
		sb.append("; HttpOnly");
	}
	if (this.sameSite != null) {
		sb.append("; SameSite=").append(this.sameSite);
	}

	response.addHeader("Set-Cookie", sb.toString());
}

Вышеупомянутое состоит в том, чтобы собрать воедино строку, затем поместить ее в заголовок и, наконец, отобразить в браузере следующим образом:

Set-Cookie: SESSION=f81d4fae-7dec-11d0-a765-00a0c91e6bf6; Path=/context-root; Secure; HttpOnly

Обработка jvm_router

существуетCookieКод чтения и записиjvmRouteОценка этого атрибута и соответствующая логика обработки.

1. ЧитатьCookieфрагмент кода в

if (this.jvmRoute != null && sessionId.endsWith(this.jvmRoute)) {
	sessionId = sessionId.substring(0,
			sessionId.length() - this.jvmRoute.length());
}

2. Напишите ответCookieфрагмент кода в

if (this.jvmRoute != null) {
	actualCookieValue = requestedCookieValue + this.jvmRoute;
}

jvm_routeдаNginxМодуль в , роль которого заключается в передачеsession cookieспособ получитьsessionвязкость. если вcookieа такжеurlне вsession, то это простоround-robinБалансировка нагрузки. Конкретный процесс делится на следующие этапы:

  • 1. Пришел первый запрос, не принесяsessionИнформация,jvm_routeпросто согласноround robinПолитика отправлена ​​одномуtomcatвыше.
  • 2.tomcatдобавитьsessionИнформация и возвращение к клиентам.
  • 3. Пользователь снова запрашивает,jvm_routeВидетьsessionЕсли есть имя внутреннего сервера, он перенаправляет запрос на соответствующий сервер.

По сути,jvm_routeтакже решитьsessionОбщее решение. это иSpringSession Series — схема реализации распределенного сеансаупоминается вIP-HASHспособ чем-то похож. Опять же, проблема здесь в том, что она не может быть решена после простояsessionПроблема передачи данных в том, что они теряются при выходе из строя.

DefaultCookieSerializerКромеCookieПосле прочтения и написания есть некоторые детали, на которые стоит обратить внимание, например:CookieПроверка медианы,remember-meреализация и др.

Ссылаться на