SpringSession header/cookie/attribute存放 SessionID(死磕)

疯狂创客圈 Java 高并发【 亿级流量聊天室实战】实战系列 【博客园总入口

架构师成长+面试必备之 高并发基础书籍 【Netty Zookeeper Redis 高并发实战


前言

Crazy-SpringCloud 微服务脚手架 &视频介绍

Crazy-SpringCloud 微服务脚手架,是为 Java 微服务开发 入门者 准备的 学习和开发脚手架。并配有一系列的使用教程和视频,大致如下:

高并发 环境搭建 图文教程和演示视频,陆续上线:

中间件 链接地址
Linux Redis 安装(带视频) Linux Redis 安装(带视频)
Linux Zookeeper 安装(带视频) Linux Zookeeper 安装, 带视频
Windows Redis 安装(带视频) Windows Redis 安装(带视频)
RabbitMQ 离线安装(带视频) RabbitMQ 离线安装(带视频)
ElasticSearch 安装, 带视频 ElasticSearch 安装, 带视频
Nacos 安装(带视频) Nacos 安装(带视频)

Crazy-SpringCloud 微服务脚手架 图文教程和演示视频,陆续上线:

组件 链接地址
Eureka Eureka 入门,带视频
SpringCloud Config springcloud Config 入门,带视频
spring security spring security 原理+实战
Spring Session SpringSession 独立使用
分布式 session 基础 RedisSession (自定义)
重点: springcloud 开发脚手架 springcloud 开发脚手架
SpingSecurity + SpringSession 死磕 (写作中) SpingSecurity + SpringSession 死磕

小视频以及所需工具的百度网盘链接,请参见 疯狂创客圈 高并发社群 博客

场景和问题

由于 SpingSecurity + SpringSession 整合场景,涉及到SpringSession SessionID 存取的问题。

具体问题:

由 SpringSecurity 将sessionID放在了 request 的 attribute中, SpringSession 需要从 request 的 attribute中取得。

SpringSession 自带的 sessionId 存取器:

SpringSession中对于sessionId的存取相关的策略,是通过HttpSessionIdResolver这个接口来体现的。HttpSessionIdResolver有两个实现类:

1: SpringSession header 存取 SessionID

HeaderHttpSessionIdResolver,通过从请求头header中解析出sessionId。

具体地说,这个实现将允许使用HeaderHttpSessionIdResolver(String)来指定头名称。还可以使用便利的工厂方法来创建使用公共头名称(例如“X-Auth-Token”和“authenticing-info”)的实例。创建会话时,HTTP响应将具有指定名称和sessionId值的响应头。

如果要使用HeaderHttpSessionIdResolver ,方法为

增加Spring Bean,类型为 HeaderHttpSessionIdResolver

import org.springframework.context.annotation.Bean;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.http.HeaderHttpSessionIdResolver; //设置session失效时间为30分钟
@EnableRedisHttpSession(maxInactiveIntervalInSeconds= 1800)
public class HttpSessionConfig { @Bean
public HeaderHttpSessionIdResolver headerHttpSessionIdResolver() {
return new HeaderHttpSessionIdResolver("x-auth-token");
} }

sessionID放到header中可以实现共享了

更加完整的内容,参见 博文

2: SpringSession cookie 存取 SessionID

这种策略对应的实现类是CookieHttpSessionIdResolver,通过从Cookie中获取session。

下面为 CookieHttpSessionIdResolver 源码, 仅供参考。如果不做定制, SpringSession 默认的 IdResolver 就是这种了。

/*
* Copyright 2014-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/ package org.springframework.session.web.http; import java.util.List; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.springframework.session.web.http.CookieSerializer.CookieValue; public final class CookieHttpSessionIdResolver implements HttpSessionIdResolver { private static final String WRITTEN_SESSION_ID_ATTR = CookieHttpSessionIdResolver.class
.getName().concat(".WRITTEN_SESSION_ID_ATTR"); private CookieSerializer cookieSerializer = new DefaultCookieSerializer(); //重点:从cookie 取得sessionid
@Override
public List<String> resolveSessionIds(HttpServletRequest request) {
return this.cookieSerializer.readCookieValues(request);
} //重点:设置 sessionid 到 cookie
@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);
this.cookieSerializer
.writeCookieValue(new CookieValue(request, response, sessionId));
} @Override
public void expireSession(HttpServletRequest request, HttpServletResponse response) {
this.cookieSerializer.writeCookieValue(new CookieValue(request, response, ""));
} /**
* Sets the {@link CookieSerializer} to be used.
*
* @param cookieSerializer the cookieSerializer to set. Cannot be null.
*/
public void setCookieSerializer(CookieSerializer cookieSerializer) {
if (cookieSerializer == null) {
throw new IllegalArgumentException("cookieSerializer cannot be null");
}
this.cookieSerializer = cookieSerializer;
} }

3 SpringSession Attribute 存取 SessionID

如果要从 Attribute 存取 SessionID ,则必须实现一个定制的 HttpSessionIdResolver,代码如下:

package com.crazymaker.springcloud.standard.config;

import com.crazymaker.springcloud.common.constants.SessionConstants;
import lombok.Data;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.session.web.http.HeaderHttpSessionIdResolver;
import org.springframework.session.web.http.HttpSessionIdResolver;
import org.springframework.util.StringUtils; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Collections;
import java.util.List; @Data
public class CustomedSessionIdResolver implements HttpSessionIdResolver { private RedisTemplate<Object, Object> redisTemplet = null; private static final String HEADER_AUTHENTICATION_INFO = "Authentication-Info"; private final String headerName; /**
* Convenience factory to create {@link HeaderHttpSessionIdResolver} that uses
* "X-Auth-Token" header.
*
* @return the instance configured to use "X-Auth-Token" header
*/
public static HeaderHttpSessionIdResolver xAuthToken() {
return new HeaderHttpSessionIdResolver(SessionConstants.SESSION_SEED);
} /**
* Convenience factory to create {@link HeaderHttpSessionIdResolver} that uses
* "Authentication-Info" header.
*
* @return the instance configured to use "Authentication-Info" header
*/
public static HeaderHttpSessionIdResolver authenticationInfo() {
return new HeaderHttpSessionIdResolver(HEADER_AUTHENTICATION_INFO);
} /**
* The name of the header to obtain the session id from.
*
* @param headerName the name of the header to obtain the session id from.
*/
public CustomedSessionIdResolver(String headerName) {
if (headerName == null) {
throw new IllegalArgumentException("headerName cannot be null");
}
this.headerName = headerName;
} //重点,springsession 用来获得sessionID
@Override
public List<String> resolveSessionIds(HttpServletRequest request) {
String headerValue = request.getHeader(this.headerName);
if (StringUtils.isEmpty(headerValue)) {
headerValue = (String) request.getAttribute(SessionConstants.SESSION_SEED);
if (!StringUtils.isEmpty(headerValue)) { headerValue = SessionConstants.getRedisSessionID(headerValue); }
}
if (StringUtils.isEmpty(headerValue)) {
headerValue = (String) request.getAttribute(SessionConstants.SESSION_ID);
} return (headerValue != null) ?
Collections.singletonList(headerValue) : Collections.emptyList();
} //重点,springsession 用来存放sessionid
@Override
public void setSessionId(HttpServletRequest request, HttpServletResponse response,
String sessionId) {
response.setHeader(this.headerName, sessionId);
} @Override
public void expireSession(HttpServletRequest request, HttpServletResponse response) {
response.setHeader(this.headerName, "");
} /**
* hash的赋值去设置
*
* @param key key
* @param hkey hkey
* @param value value
*/
public void hset(String key, String hkey, String value) {
redisTemplet.opsForHash().put(key, hkey, value);
} /**
* hash的赋值去取值
*
* @param key key
* @param hkey hkey
*/
public String hget(String key, String hkey) {
return (String) redisTemplet.opsForHash().get(key, hkey);
} public Object getSessionId(String loginName) {
return hget(SessionConstants.SESSION_ID + ":KEYS", loginName);
} public void setSessionId(String loginName, String sid) {
hset(SessionConstants.SESSION_ID + ":KEYS", loginName, sid);
} }

SpringSession SessionID 存取 原理

牛逼的 SessionRepositoryFilter 过滤器: 位于 spring-session-core 包中,间接涉及到 SpringSession 的ID的获取和保存。

SessionRepositoryFilter 作为 SpringSession 的重要的一环,涉及两个非常重要的工作:

(1)请求处理前,SessionRepositoryFilter 通过多层函数调用, 从 HttpSessionIdResolver 中取得 SessionID。

(2)请求 处理完成后,SessionRepositoryFilter 负责session的提交(如:保存到redis),并且通过 HttpSessionIdResolver 输出sessionID。



近景图

具体,请关注 Java 高并发研习社群博客园 总入口


最后,介绍一下疯狂创客圈:疯狂创客圈,一个Java 高并发研习社群博客园 总入口

疯狂创客圈,倾力推出:面试必备 + 面试必备 + 面试必备 的基础原理+实战 书籍 《Netty Zookeeper Redis 高并发实战


疯狂创客圈 Java 死磕系列

  • Java (Netty) 聊天程序【 亿级流量】实战 开源项目实战

SpringSession header/cookie/attribute存放 session id的更多相关文章

  1. 【转】Session ID/session token 及和cookie区别

    Session + Cookie  知识收集! cookie机制采用的是在客户端保持状态的方案.它是在用户端的会话状态的存贮机制,他需要用户打开客户端的cookie支持.cookie的作用就是为了解决 ...

  2. HTTP基础--cookie机制和session机制

    1.介绍cookie和session的区别,怎么获取与使用?(这个问题比较开放,可深可浅,现在将这里涉及的主要问题总计如下答案) 答: 一.cookie机制和session机制的区别 cookie机制 ...

  3. cookie机制和session机制的原理和区别[转]

    一.cookie机制和session机制的区别 具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案. 同时我们也看到,由于在服务器端保持状态的 ...

  4. cookie机制和session机制的区别(面试题)

    一.cookie机制和session机制的区别 具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案. 同时我们也看到,由于才服务器端保持状态的 ...

  5. PHP cookie禁用时session 方案

    在PHP中使用过SESSION的朋友可能会碰到这么一个问题,SESSION变量不能跨页传递.这令我苦恼了好些日子,最终通过查资料思考并解决了这个问题.我认为,出现这个问题的原因有以下几点: 1.客户端 ...

  6. Cookie禁用 获取session

    转自:http://blog.csdn.net/u010433704/article/details/40950599 Cookie与 Session,一般认为是两个独立的东西,Session采用的是 ...

  7. 关于PHP中浏览器禁止Cookie后,Session能使用吗?

    sessionid是存储在cookie中的,解决方案如下: Session URL重写,保证在客户端禁用或不支持COOKIE时,仍然可以使用Session session机制.session机制是一种 ...

  8. php中如何传递Session ID

    一般通过在各个页面之间传递的唯一的 Session ID,并通过 Session ID 提取这个用户在服务器中保存的 Session 变量,来跟踪一个用户.常见的 Session ID 传送方法主要有 ...

  9. Session id实现通过Cookie来传输方法及代码参考

    1. Web中的Session指的就是用户在浏览某个网站时,从进入网站到浏览器关闭所经过的这段时间,也就是用户浏览这个网站所花费的时间.因此从上述的定义中我们可以看到,Session实际上是一个特定的 ...

随机推荐

  1. ELK-logstash基本用法

    一:logstash介绍 Logstash在elk系统中为数据存储,报表查询和日志解析创建了一个功能强大的管道链.Logstash提供了多种多样的 input,filters,codecs和outpu ...

  2. python爬虫--selenium模块.上来自己动!

    selenium 基本操作 from selenium import webdriver from time import sleep #实例化一个浏览器对象 bro = webdriver.Chro ...

  3. 关于toString的自动调用

    class a{ } class b extends a{ String rr = "zzz"; public String toString(){ return "aa ...

  4. 《Java基础知识》序列化与反序列化详解

    序列化的作用:为了不同jvm之间共享实例对象的一种解决方案.由java提供此机制. 序列化应用场景: 1. 分布式传递对象. 2. 网络传递对象. 3. tomcat关闭以后会把session对象序列 ...

  5. Redis Cluster 的数据分片机制

    上一篇<分布式数据缓存中的一致性哈希算法> 文章中讲述了一致性哈希算法的基本原理和实现,今天就以 Redis Cluster 为例,详细讲解一下分布式数据缓存中的数据分片,上线下线时数据迁 ...

  6. 【BZOJ 3771】Triple

    Problem Description 给出 \(n\) 个物品,第 \(i\) 个物品体积为 \(a_i\) . 对于每个体积 \(V\) ,求选出 \(3\) 个物品,体积之和为 \(V\) 的方 ...

  7. Maven 项目在 Eclipse 的创建配置

    第1步 New 菜单 Other.. -> Maven -> Maven Project ,然后单击 Next .如下图所示 第2步 在New Maven Project向导中,选择Cre ...

  8. javaWeb实现验证码--代码超简单

    1.前端显示 HTML: <h3>验证码:</h3> <input type="text" name="validationCode&quo ...

  9. 2019有赞中高级Java工程师面试题与解答

    说说JVM的内存分区 线程私有的区域 程序计数器:JVM中程序计数器相当于汇编语言中的CPU中的寄存器,保存程序当前执行的指令的地址. 虚拟机栈:Java方法执行的栈由许多个栈帧构成,每个栈帧对应一个 ...

  10. js实现常见排序算法

    电脑配置 CPU:AMD X4 640 内存: 宏想 DDR3 1600MHz 8g 主板:华擎 980DE3/U3S3 R2.0 浏览器:chrome 79.0.3945.88(正式版本) (64 ...