上一篇文章中,我们使用Redis集成了Spring Session。大多数的配置都是Spring Boot帮我们自动配置的,这一节我们介绍一点Spring Session较为高级的特性。

集成Spring Security

之所以把Spring Session和Spring Security放在一起讨论,是因为我们的应用在集成Spring Security之后,用户相关的认证与Session密不可分,如果不注意一些细节,会引发意想不到的问题。

与Spring Session相关的依赖可以参考上一篇文章,这里给出增量的依赖:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

我们引入依赖后,就已经自动配置了Spring Security,我们在application.yml添加一个内存中的用户:

security:
user:
name: admin
password: admin

测试登录点沿用上一篇文章的端点,访问http://localhost:8080/test/cookie?browser=chrome端点后会出现http basic的认证框,我们输入admin/admin,即可获得结果,也遇到了第一个坑点,我们会发现每次请求,sessionId都会被刷新,这显然不是我们想要的结果。

诡异的运行结果

这个现象笔者研究了不少源码,但并没有得到非常满意的解释,只能理解为SecurityAutoConfiguration提供的默认配置,没有触发到响应的配置,导致了session的不断刷新(如果读者有合理的解释可以和我沟通)。
Spring Session之所以能够替换默认的tomcat httpSession是因为配置了springSessionRepositoryFilter这个过滤器,且提供了非常高的优先级,这归功于AbstractSecurityWebApplicationInitializer ,AbstractHttpSessionApplicationInitializer 这两个初始化器,当然,也保证了Spring Session会在Spring Security之前起作用。

而解决上述的诡异现象也比较容易(但原理不清),我们使用@EnableWebSecurity对Spring Security进行一些配置,即可解决这个问题

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()//<1>
.and()
.logout().permitAll();
} @Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin").password("admin").roles("USER");//<2>
} }

<1> 不想大费周章写一个登录页面,于是开启了http basic认证

<2> 配置了security config之后,springboot的autoConfig就会失效,于是需要手动配置用户。

再次请求,可以发现SessionId返回正常,@EnableWebSecurity似乎触发了相关的配置,当然了,我们在使用Spring Security时不可能使用autoconfig,但是这个现象的确是一个疑点。

使用自定义CookieSerializer

@Bean
public CookieSerializer cookieSerializer() {
DefaultCookieSerializer serializer = new DefaultCookieSerializer();
serializer.setCookieName("JSESSIONID");
serializer.setCookiePath("/");
serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");
return serializer;
}

使用上述配置后,我们可以将Spring Session默认的Cookie Key从SESSION替换为原生的JSESSIONID。而CookiePath设置为根路径且配置了相关的正则表达式,可以达到同父域下的单点登录的效果,在未涉及跨域的单点登录系统中,这是一个非常优雅的解决方案。如果我们的当前域名是moe.cnkirito.moe,该正则会将Cookie设置在父域cnkirito.moe中,如果有另一个相同父域的子域名blog.cnkirito.moe也会识别这个Cookie,便可以很方便的实现同父域下的单点登录。

根据用户名查找用户归属的SESSION

这个特性听起来非常有意思,你可以在一些有趣的场景下使用它,如知道用户名后即可删除其SESSION。一直以来我们都是通过线程绑定的方式,让用户操作自己的SESSION,包括获取用户名等操作。但如今它提供了一个反向的操作,根据用户名获取SESSION,恰巧,在一些项目中真的可以使用到这个特性,最起码,当别人问起你,或者讨论到和SESSION相关的知识时,你可以明晰一点,这是可以做到的。

我们使用Redis作为Session Store还有一个好处,就是其实现了FindByIndexNameSessionRepository接口,下面让我们来见证这一点。

@Controller
public class CookieController {
@Autowired
FindByIndexNameSessionRepository<? extends ExpiringSession> sessionRepository; @RequestMapping("/test/findByUsername")
@ResponseBody
public Map findByUsername(@RequestParam String username) {
Map<String, ? extends ExpiringSession> usersSessions = sessionRepository.findByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, username);
return usersSessions;
}
}

由于一个用户可能拥有多个Session,所以返回的是一个Map信息,而这里的username,则就是与Spring Security集成之后的用户名,最令人感动Spring厉害的地方,是这一切都是自动配置好的。我们在内存中配置的用户的username是admin,于是我们访问这个端点,可以看到如下的结果

用户名访问session

连同我们存入session中的browser=chrome,browser=360都可以看见(只有键名)。

总结

Spring Session对各种场景下的Session管理提供一套非常完善的实现。笔者所介绍的,仅仅是Spring Session常用的一些特性,更多的知识点可以在spring.io的文档中一览无余,以及本文中作者存在的一个疑惑,如有兴趣可与我沟通。

https://www.cnkirito.moe/spring-session-3/

spring boot实现session 同步共享及 根据sessionid 获取相应的session

一:首先 引入相应架包(装上redis 服务)
pom.xml 添加如下:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-redis</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>

二,配置文件yml添加如下(或者采用.properties方式添加):

redis:
host: 192.168.1.11
port: 6379
# REDIS (RedisProperties)
# Redis数据库索引(默认为0)
database: 0
# Redis服务器连接密码(默认为空)
password:
# 连接池最大连接数(使用负值表示没有限制)
# 连接超时时间(毫秒)
timeout: 0
pool:
max-active: 8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1
# 连接池中的最大空闲连接
max-idle: 8
# 连接池中的最小空闲连接
min-idle: 0

三,启动类添加注解@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 60*30):
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
@SpringBootApplication
@ServletComponentScan
@Configuration
@EnableDiscoveryClient
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 60*30)
public class ProviderBdApplication extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(ProviderBdApplication.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
logger.info("启动加载自定义的ServletInitializer");
return application.sources(ProviderBdApplication.class);
}
}

四, 存取sesion
经过以上步骤 ,就实现了session 共享功能,
存入session:request.getSession().setAttribute("loginUser", User);
//根据id 获取 session
@Resource(name="sessionRepository")
private SessionRepository<ExpiringSession> sessionRepository;

Strign sessionId = session.getId();//此处session 可以根据传 入参数获取
ExpiringSession session = sessionRepository.getSession(sessionId );// 根据sessionid 获取 session 同而实现共享
User user = session.getAttribute("loginUser");
---------------------
作者:氼兲戦S無撩
来源:CSDN
原文:https://blog.csdn.net/qq_33545491/article/details/78560156
版权声明:本文为博主原创文章,转载请附上博文链接!

Re:从零开始的Spring Session(三)的更多相关文章

  1. Re:从零开始的Spring Session(二)

    上一篇文章介绍了一些Session和Cookie的基础知识,这篇文章开始正式介绍Spring Session是如何对传统的Session进行改造的.官网这么介绍Spring Session: Spri ...

  2. Re:从零开始的Spring Session(一)

    Session和Cookie这两个概念,在学习java web开发之初,大多数人就已经接触过了.最近在研究跨域单点登录的实现时,发现对于Session和Cookie的了解,并不是很深入,所以打算写两篇 ...

  3. (转)从零开始的Spring Session(一)

    Session和Cookie这两个概念,在学习java web开发之初,大多数人就已经接触过了.最近在研究跨域单点登录的实现时,发现对于Session和Cookie的了解,并不是很深入,所以打算写两篇 ...

  4. 从零开始的Spring Session(一)

    Session和Cookie这两个概念,在学习java web开发之初,大多数人就已经接触过了.最近在研究跨域单点登录的实现时,发现对于Session和Cookie的了解,并不是很深入,所以打算写两篇 ...

  5. 从零开始学spring cloud(三) -------- Eureka简介

    1.服务发现组件:Eureka Eureka的开源文档介绍地址:https://github.com/Netflix/eureka/wiki/Eureka-at-a-glance What is Eu ...

  6. (38)Spring Boot分布式Session状态保存Redis【从零开始学Spring Boot】

    [本文章是否对你有用以及是否有好的建议,请留言] 在使用spring boot做负载均衡的时候,多个app之间的session要保持一致,这样负载到不同的app时候,在一个app登录之后,而访问到另外 ...

  7. Re:从零开始的Spring Security Oauth2(三)

    上一篇文章中我们介绍了获取token的流程,这一篇重点分析一下,携带token访问受限资源时,内部的工作流程. @EnableResourceServer与@EnableAuthorizationSe ...

  8. 57. Spring 自定义properties升级篇【从零开始学Spring Boot】

    之前在两篇文章中都有简单介绍或者提到过 自定义属性的用法: 25.Spring Boot使用自定义的properties[从零开始学Spring Boot] 51. spring boot属性文件之多 ...

  9. 81. Spring Boot集成JSP疑问【从零开始学Spring Boot】

    [原创文章,转载请注明出处] 针对文章: ()Spring Boot 添加JSP支持[从零开始学Spring Boot] 有网友提了这么一些疑问: 1.Spring Boot使用jsp时,仍旧可以打成 ...

随机推荐

  1. 动态规划--求最大连续子数组的和(Python实现)&求解最大连续乘积字串(Python实现)

    def MaxSum(self,array,n): sum=array[0] result=array[0] for i in range(0,n): if sum<0: sum=a[i] el ...

  2. 8.正则表达式和XPath

    1.使用正则表达式爬取内涵段子 import requests import re def loadPage(page): url = "http://www.neihan8.com/art ...

  3. maven-java包管理工具-01

    maven只用来管理java项目,也是用java开发的 传统的项目因为包的管理有很多问题,所以才有的maven的诞生: 1. 项目开始的时候,确定项目中可能要使用到的包,然后下载包,复制粘贴到项目里面 ...

  4. ServiceStack 多租户的实现方案

    以SqlServer为例子说明ServiceStack实现多租户,在SqlServer中创建4个Database:TMaster.T1,T2,T3,为了安全起见 每个Database不用sa账号,而是 ...

  5. 关于Winform下DataGridView中实现checkbox全选反选、同步列表项的处理

    近期接手一个winform 项目,虽然之前有.net 的经验,但是对一些控件的用法还不是很熟悉. 这段时间将会记录一些在工作中遇到的坎坷以及对应的解决办法,写出来与大家分享并希望大神提出更好解决方法来 ...

  6. 「PKUSC2018」星际穿越(倍增)

    倍增好题啊! 我们我们预处理 \(f[x][i]\) 表示 \(x\) 点最左到达的端点,\(sum[x][i]\) 表示 \(x\) 点最左到达的端点时 \(f[x][i]\sim x\) 的答案, ...

  7. mysql多列索引和最左前缀

    数据库的索引可以加快查询速度,原因是索引使用特定的数据结构(B-Tree)对特定的列额外组织存放,加快存储引擎(索引是存储引擎实现)查找记录的速度.索引优化是数据库优化的最重要手段. 如果查询语句使用 ...

  8. 使用httpClient模拟http请求

    在很多场景下都需要用到java代码来发送http请求:如和短信后台接口的数据发送,发送数据到微信后台接口中: 这里以apache下的httpClient类来模拟http请求:以get和Post请求为例 ...

  9. Swfit 里 Array(五)和 NSArray 转换

     只看 Swift Array 到 NSArray Array 里的源代码 extension Array { @inlinable public // @SPI(Foundation) func ...

  10. Shell - 简明Shell入门12 - 定制输出(ColorOutput)

    示例脚本及注释 #!/bin/bash echo -e "\033[32m" # 设置输出属性,绿色字体 echo "This is a test!" echo ...