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. ES6,箭头函数 (=>)注意点

    函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象. 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误. 不可以使用arguments对象,该对象在函数体内不存 ...

  2. vue中通过.sync修饰符实现子组件修改父组件数据

    vue父子通讯是单向数据流,也就是子组件不能修改父组件的值,但是在一些情况下是需要这样做的. 先看官方文档: 接下来举例实现 1.实现一个双向数据绑定,子组件改变的时候,父组件也在改变 父组件 < ...

  3. Vue如何实现数据响应的

    参考博客:https://medium.com/vue-mastery/the-best-explanation-of-javascript-reactivity-fea6112dd80d 翻译博客: ...

  4. 自建CA证书搭建https服务器

    由于CA收费,所以可以自建CA,通过将CA导入浏览器实现https的效果,曾经12306购票就需要自行导入网站证书. 关于https 2015年阿里巴巴将旗下淘宝.天猫(包括移动客户端)全站启用HTT ...

  5. 集群式Quartz定时任务框架实践

    在日常开发汇总,经常会遇到需要定时任务的场景,简单的,可以使用Spring的定时任务调度框架,也可以使用Quartz.无论使用哪种,都需要解决一个问题,那就是集群问题.一般情况下,定时任务能且仅能运行 ...

  6. ORA-19625: error identifying file

    问题描述:rman进行备份的时候,出现报错ORA-19625,无效的文件 1.进行数据库备份,然后就出现了报错,没有这个24号的归档日志 RMAN> run{ 2> allocate ch ...

  7. 深入学习socket网络编程,以java语言为例

    了解java的socket编程与Linux Socket API之间的关系 一.java的网络编程 1.socket原理 socket通信就是通过IP和端口号将两台主机建立连接,提供通信.主机A的应用 ...

  8. 用js写直角三角形,等腰三角形,菱形

    //一. 画一个直角三角形     // 第几行   *号数     // *        1        1       // **       2        2     // ***    ...

  9. three.js 制作太阳系统

    最近学了three.js,想拿来练练手,喜欢宇宙,于是亲手撸代码来完成这个,为了更真实,于是查了一些相关资料.1. 距离太阳由近及远分别是[水星,金星,地球,火星,木星,土星,天王星,海王星]2. 他 ...

  10. Linux 的目录结构

    原文内容来自于LZ(楼主)的印象笔记,如出现排版异常或图片丢失等问题,可查看当前链接:https://app.yinxiang.com/shard/s17/nl/19391737/cbbf47b0-f ...