Spring Session产生的sessionid与cookies中的sessionid不一样的问题 httpOnly 设置不起作用

本文主要是介绍Spring Session产生的sessionid与cookies中的sessionid不一样的问题 httpOnly 设置不起作用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

摘自 : https://www.cnblogs.com/imyjy/p/9187168.html
背景:
  Springboot 2.0 (spring-session-data-redis + spring-boot-starter-web)
需求:

通过cookies中取到的 sessionid 获取到 session

预期效果:

@Autowired

private SessionRepositry sessionRepositry;

Session session = sessionRespositry.findById(sessionId);

真实结果: 获取到的session是null, 然而通过 request.getSession(); 可以获取到session, 说明 session是存在的.

问题追踪后发现问题:

cookie中的sessionId 与 session.getId() 不一样!!!

DEBUG:
  1. 先看一看SpringSession是如何从Cookie中获取sessionid的! (相关类: org.springframework.session.web.http.DefaultCookieSerializer)
在这里插入图片描述

2. 再看一看 useBase64Encoding 的值是啥, 首先看默认值

在这里插入图片描述

3. 看看这些配置是在哪里被(赋值)确认的, 一路追踪到 org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration 配置类中

在这里插入图片描述
 看看 createDefaultCookieSerializer() 是如何实现的

在这里插入图片描述

4. 从上面可以得出结论, 我们无法 通过配置文件 中 server.servlet.session.** 来配置 useBase64Encoding. 使 cookie中的 sessionid 与 session.getId() 保持一致

5. 期间发现的另一个问题: 虽然 sessionCookieConfig 有httpOnly相关配置, 但这里并未将配置设入 cookieSerializer 中, 导致配置文件中的 server.servlet.session.cookie.httpOnly = false 不起作用

解决方案:

第一种方案: 通过配置 自定义的 CookieSerializer 来指定配置信息(如果觉得麻烦请直接看第二种方案), 如下

a) 首先因为 SessionCookieConfig 接口中并没有定义 isUseBase64Encoding() 等接口, 导致缺少了部分配置, 所以我 自定义了一个 MySessionCookieConfig 接口继承了 SessionCookieConfig, 并写了一个默认实现 MyDefaultSessionCookieConfig
 
  MySessionCookieConfig

package com.cardgame.demo.center.config;import javax.servlet.SessionCookieConfig;/**** 补充 SessionCookie 中未定义的配置项* @author yjy* 2018-06-15 13:30*/
public interface MySessionCookieConfig extends SessionCookieConfig {String getDomainPattern();void setDomainPattern(String domainPattern);String getJvmRoute();void setJvmRoute(String jvmRoute);boolean isUseBase64Encoding();void setUseBase64Encoding(boolean useBase64Encoding);}

MyDefaultSessionCookieConfig

package com.cardgame.demo.center.config;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;/**** 涵盖 CookieSerializer 所有配置项* @author yjy* 2018-06-15 13:31*/
@Component
@ConfigurationProperties(prefix = "server.servlet.session.cookie")
public class MyDefaultSessionCookieConfig implements MySessionCookieConfig {private String name = "SESSION";private String path;private String domain;private String comment;private int maxAge = -1;private String domainPattern;private String jvmRoute;private boolean httpOnly = true;private boolean secure = false;private boolean useBase64Encoding = false;@Overridepublic String getDomainPattern() {return domainPattern;}@Overridepublic void setDomainPattern(String domainPattern) {this.domainPattern = domainPattern;}@Overridepublic String getJvmRoute() {return jvmRoute;}@Overridepublic void setJvmRoute(String jvmRoute) {this.jvmRoute = jvmRoute;}@Overridepublic boolean isUseBase64Encoding() {return useBase64Encoding;}@Overridepublic void setUseBase64Encoding(boolean useBase64Encoding) {this.useBase64Encoding = useBase64Encoding;}@Overridepublic String getName() {return name;}@Overridepublic void setName(String name) {this.name = name;}@Overridepublic String getPath() {return path;}@Overridepublic void setPath(String path) {this.path = path;}@Overridepublic String getDomain() {return domain;}@Overridepublic void setDomain(String domain) {this.domain = domain;}@Overridepublic String getComment() {return comment;}@Overridepublic void setComment(String comment) {this.comment = comment;}@Overridepublic boolean isHttpOnly() {return httpOnly;}@Overridepublic void setHttpOnly(boolean httpOnly) {this.httpOnly = httpOnly;}@Overridepublic boolean isSecure() {return secure;}@Overridepublic void setSecure(boolean secure) {this.secure = secure;}@Overridepublic int getMaxAge() {return maxAge;}@Overridepublic void setMaxAge(int maxAge) {this.maxAge = maxAge;}
}

b) 利用 MyDefaultSessionCookieConfig 携带的配置, 自定义 CookieSerializer Bean

package com.cardgame.demo.center.config;import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;import javax.servlet.ServletContext;
import javax.servlet.SessionCookieConfig;/**** @author yjy* 2018-06-08 14:53*/
@Slf4j
@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600, redisNamespace = "center")
public class RedisSessionConfig implements ApplicationContextAware {@Beanpublic CookieSerializer cookieSerializer(ServletContext servletContext, MySessionCookieConfig sessionCookieConfig) {DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();if (servletContext != null) {if (sessionCookieConfig != null) {if (sessionCookieConfig.getName() != null)cookieSerializer.setCookieName(sessionCookieConfig.getName());if (sessionCookieConfig.getDomain() != null)cookieSerializer.setDomainName(sessionCookieConfig.getDomain());if (sessionCookieConfig.getPath() != null)cookieSerializer.setCookiePath(sessionCookieConfig.getPath());if (sessionCookieConfig.getMaxAge() != -1)cookieSerializer.setCookieMaxAge(sessionCookieConfig.getMaxAge());if (sessionCookieConfig.getDomainPattern() != null)cookieSerializer.setDomainNamePattern(sessionCookieConfig.getDomainPattern());if (sessionCookieConfig.getJvmRoute() != null)cookieSerializer.setJvmRoute(sessionCookieConfig.getJvmRoute());cookieSerializer.setUseSecureCookie(sessionCookieConfig.isSecure());cookieSerializer.setUseBase64Encoding(sessionCookieConfig.isUseBase64Encoding());cookieSerializer.setUseHttpOnlyCookie(sessionCookieConfig.isHttpOnly());}}if (ClassUtils.isPresent("org.springframework.security.web.authentication.RememberMeServices",null)) {boolean usesSpringSessionRememberMeServices = !ObjectUtils.isEmpty(this.context.getBeanNamesForType(SpringSessionRememberMeServices.class));if (usesSpringSessionRememberMeServices) {cookieSerializer.setRememberMeRequestAttribute(SpringSessionRememberMeServices.REMEMBER_ME_LOGIN_ATTR);}}return cookieSerializer;}private ApplicationContext context;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.context = applicationContext;}
}

c) 修改配置文件配置

在这里插入图片描述

d) 配置完成后重新启动, 再看 SpringHttpSessionConfiguration 加载的时候, 拿到了我们自定义的 CookieSerializer, 我想要的配置都有了!! 打开浏览器测试通过!!
在这里插入图片描述
在这里插入图片描述

第二种方案: 拿到 Cookie 中的 sessionId 后, 手动解码, 再 通过 sessionRespositry.findById(sessionId); 获取session

a) 解码的方案 从 DefaultSerializer 类中 copy 一个 , 如下:

/*** Decode the value using Base64.* @param base64Value the Base64 String to decode* @return the Base64 decoded value* @since 1.2.2*/
private String base64Decode(String base64Value) {try {byte[] decodedCookieBytes = Base64.getDecoder().decode(base64Value);return new String(decodedCookieBytes);}catch (Exception e) {return null;}
}

b) 获取步骤:

String cookieSessionId = “XXX”;

String sessionId = base64Decode(cookieSessionId);

Session session = sessionRespositry.findById(sessionId);

c) 搞定! (此方案未解决 httpOnly 不起效的问题, 如果要解决 httpOnly = false , 请看方案一)

这篇关于Spring Session产生的sessionid与cookies中的sessionid不一样的问题 httpOnly 设置不起作用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/818426

相关文章

PostgreSQL 默认隔离级别的设置

《PostgreSQL默认隔离级别的设置》PostgreSQL的默认事务隔离级别是读已提交,这是其事务处理系统的基础行为模式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一 默认隔离级别概述1.1 默认设置1.2 各版本一致性二 读已提交的特性2.1 行为特征2.2

一文详解MySQL如何设置自动备份任务

《一文详解MySQL如何设置自动备份任务》设置自动备份任务可以确保你的数据库定期备份,防止数据丢失,下面我们就来详细介绍一下如何使用Bash脚本和Cron任务在Linux系统上设置MySQL数据库的自... 目录1. 编写备份脚本1.1 创建并编辑备份脚本1.2 给予脚本执行权限2. 设置 Cron 任务2

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4

一文详解如何在idea中快速搭建一个Spring Boot项目

《一文详解如何在idea中快速搭建一个SpringBoot项目》IntelliJIDEA作为Java开发者的‌首选IDE‌,深度集成SpringBoot支持,可一键生成项目骨架、智能配置依赖,这篇文... 目录前言1、创建项目名称2、勾选需要的依赖3、在setting中检查maven4、编写数据源5、开启热

mtu设置多少网速最快? 路由器MTU设置最佳网速的技巧

《mtu设置多少网速最快?路由器MTU设置最佳网速的技巧》mtu设置多少网速最快?想要通过设置路由器mtu获得最佳网速,该怎么设置呢?下面我们就来看看路由器MTU设置最佳网速的技巧... 答:1500 MTU值指的是在网络传输中数据包的最大值,合理的设置MTU 值可以让网络更快!mtu设置可以优化不同的网

Java对异常的认识与异常的处理小结

《Java对异常的认识与异常的处理小结》Java程序在运行时可能出现的错误或非正常情况称为异常,下面给大家介绍Java对异常的认识与异常的处理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参... 目录一、认识异常与异常类型。二、异常的处理三、总结 一、认识异常与异常类型。(1)简单定义-什么是

SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志

《SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志》在SpringBoot项目中,使用logback-spring.xml配置屏蔽特定路径的日志有两种常用方式,文中的... 目录方案一:基础配置(直接关闭目标路径日志)方案二:结合 Spring Profile 按环境屏蔽关

Java使用HttpClient实现图片下载与本地保存功能

《Java使用HttpClient实现图片下载与本地保存功能》在当今数字化时代,网络资源的获取与处理已成为软件开发中的常见需求,其中,图片作为网络上最常见的资源之一,其下载与保存功能在许多应用场景中都... 目录引言一、Apache HttpClient简介二、技术栈与环境准备三、实现图片下载与保存功能1.

SpringBoot排查和解决JSON解析错误(400 Bad Request)的方法

《SpringBoot排查和解决JSON解析错误(400BadRequest)的方法》在开发SpringBootRESTfulAPI时,客户端与服务端的数据交互通常使用JSON格式,然而,JSON... 目录问题背景1. 问题描述2. 错误分析解决方案1. 手动重新输入jsON2. 使用工具清理JSON3.

java中long的一些常见用法

《java中long的一些常见用法》在Java中,long是一种基本数据类型,用于表示长整型数值,接下来通过本文给大家介绍java中long的一些常见用法,感兴趣的朋友一起看看吧... 在Java中,long是一种基本数据类型,用于表示长整型数值。它的取值范围比int更大,从-922337203685477