Spring Session 详解

1.SpringSession简介

1.1 Session 会话管理及带来的问题

HTTP协议本身是无状态,的为了保存会话信息,浏览器Cookie通过SessionID标识会话请求,服务器以SessionID为key来存储会话信息。 在 Web 项目开发中, Session 会话管理是一个很重要的部分, 用于存储与记录用户的状态或相关的数据。

  • 通常情况下 session 交由容器(tomcat) 来负责存储和管理, 但是如果项目部署在多台tomcat 中, 则 session 管理存在很大的问题
  • 多台 tomcat 之间无法共享 session, 比如用户在 tomcat A 服务器上已经登录了, 但当负载均衡跳转到 tomcat B 时, 由于 tomcat B 服务器并没有用户的登录信息,session 就失效了, 用户就退出了登录
  • 一旦 tomcat 容器关闭或重启也会导致 session 会话失效因此如果项目部署在多台 tomcat 中, 就需要解决 session 共享的问题

1.2 SpringSession的特性

使用框架的会话管理工具,也就是我们要介绍的 Spring session,这个方案既不依赖 tomcat 容器, 又不需要改动代码, 由 Spring session 框架为我们提供, 可以说是目前非常完美的 session 共享解决方案。Spring Session 是 Spring 家族中的一个子项目, 它提供一组 API 和实现, 用于管理用户的 session 信息.它把 servlet 容器实现的 httpSession 替换为 spring-session, 专注于解决 session 管理问题, Session 信息存储在 Redis 中, 可简单快速且无缝的集成到我们的应用中;

Spring Session 的特性:

  • 提供用户 session 管理的 API 和实现
  • 提供 HttpSession, 以中立的方式取代 web 容器的 session, 比如 tomcat 中的session
  • 支持集群的 session 处理, 不必绑定到具体的 web 容器去解决集群下的 session共享问题

2.入门案例

2.1 创建项目

(1)创建一个Maven的web module,名字为01-springsession-web
在这里插入图片描述(2)完善Maven项目的结构

  • 在main目录下,创建java目录,并标记为Sources Root
    在这里插入图片描述
  • 在main目录下,创建resources目录,并标记为Resources Root
    在这里插入图片描述
  • 导入依赖
<!--servlet依赖-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
    </dependency>
    <!--SpringSession redis 集成依赖-->
    <dependency>
      <groupId>org.springframework.session</groupId>
      <artifactId>spring-session-data-redis</artifactId>
      <version>1.3.1.RELEASE</version>
    </dependency>
    <!--Spring Web 模块依赖-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-web</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>

2.2 代码开发

(1) 创建向 session 放数据的 servlet

package session.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(urlPatterns = "/setSession")
public class SetSessionServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.getSession().setAttribute("url","http://www.baidu.com");
        resp.getWriter().write("OK");
    }
}

(2) 创建从 session 中获取数据的 servlet

package session.servlet;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(urlPatterns = "/getSession")
public class GetSessionServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req,resp);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String url= (String) req.getSession().getAttribute("url");
        resp.getWriter().write(url==null?"NO Session":url);
    }
}

(3)部署访问测试(目前无法实现 session 共享)

  • 配置tomcat9100 服务器,给 tomcat 服务器取名,并修改端口号,并将项目部署到tomcat9100 上

在这里插入图片描述

  • 配置tomcat9200服务器,操作步骤同上

可以在9100端口的服务器上访问/setSession,再在9200端口的服务器上访问 /getSession
这个时候我们通过测试会发现两个Tomcat服务器之间是无法共享session数据的

2.3 SpringSession 集成配置

  • 在resources目录下创建如下两个配置文件在这里插入图片描述
  • applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <import resource="classpath:springsession.xml"/>
</beans>
  • springsession.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--
        启动Spring的注解支持,因为SpringSession中使用到了Spring的相关注解,因此需要启动Spring的注解,这一步是可以省略的
        通常工作时我们会使用 <context:component-scan base-package="com"/>来进行包扫描,这个标签中的功能就包含了
        <context:annotation-config/>的功能,因此实际工作时这个步骤是可以省略
     -->
    <context:annotation-config/>

    <!--
         定义一个用于配置SpringSession的bean标签配置
         只配置RedisHttpSessionConfiguration 的Bean 就可以实现同域名同项目的Session共享
         适合于我们的Nginx集群模式下的P2P项目部署
    -->
    <bean id="redisHttpSessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
        <!--配置Session的最大生命周期 单位 秒 默认值为1800 表示30分钟 -->
        <property name="maxInactiveIntervalInSeconds" value="1800"/>
    </bean>


    <!-- 配置 jedis 连接工厂, 用于连接 redis
         可选配置步骤,如果当前工程已经配置过了redis,那么这个过程可以省略
    -->
    <bean id="jedisConnectionFactory"
          class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
          <!--分别为主机名、redis端口号、redis密码-->
        <property name="hostName" value="127.0.0.1"/> 
        <property name="port" value="6379"/>
        <property name="password" value="123456" />
    </bean>
</beans>
  • 点击 config 将这两个配置文件进行关联
    在这里插入图片描述

这次通过上面已经介绍过的测试方法,我们可以发现session数据可以在端口号分别为9100和9200的两个不同的Tomcat服务器上实现共享了


  • 在浏览器(这里我使用的谷歌浏览器)上检查页面元素会发现两个页面上存储的cookie中存储的Session ID属性值和redis中相同。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 上面的HASH文本框中便是redis上存储的Session ID值
  • lastAccessTime:最后一次访问时间
  • sessionAttr:session对象中存储数的属性
  • maxIntactiveInterval:session的最大生命周期,默认是30分钟
  • creationTime:session的创建时间

3.同域名下不同项目的session共享

3.1 案例

  1. 在 Deployment 选项卡下,设置本地 tomcat9100的Application context 为/p2p
  2. 在 Deployment 选 项卡下 ,设置本地 tomcat9200的Application context 为/shop
  3. 在idea中重新启动本地的两台 tomcat 服务器
  4. 在浏览器中访问 tomcat9100(p2p), 设置 session
    在这里插入图片描述
    session设置成功

  5. 在浏览器中访问 tomcat9200(shop),获取 session
    在这里插入图片描述
    获取不到session

  6. 分析 Session 共享失败原因
  • 我们通过浏览器提供的开发人员工具可以发现,这两个请求的 cookie 的路径(path)不一致(如下图),虽然我们已经加了Spring Session共享机制,但是后台服务器认为这是两个不同的会话(session),可以通过 Redis 客户端工具(Redis Destop Mananger) 查看,先清空,然后访问,发现是维护了两个不同的 session,所以不能实现共享。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 同样redis中也存储了两个不同的session对象,其中一个session对象中没有sessionAttr属性。
    在这里插入图片描述
    在这里插入图片描述
  1. 解决方案:设置Cookie路径为根/上下文在springsession.xml文件中,加如下配置:
<bean id="redisHttpSessionConfiguration" class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
        <!--配置Session的最大生命周期 单位 秒 默认值为1800 表示30分钟 -->
        <property name="maxInactiveIntervalInSeconds" value="1800"/>
        <!--注入一个Cookie的序列化规则对象 -->
        <property name="cookieSerializer" ref="defaultCookieSerializer"/>
</bean>

    <!--配置一个Cookie序列化规则对象 用于改变Cookie的存放规则 -->
<bean id="defaultCookieSerializer" class="org.springframework.session.web.http.DefaultCookieSerializer">
        <!--指定SpringSession的SessionId存放在域名的根路径下,用于实现同域名不同项目的Session共享 -->
        <property name="cookiePath" value="/" />
</bean>
  1. 重新进行测试发现两个不同项目的session数据也能实现共享,且两个请求的cookie路径(path)相同均为" / "。且此时redis中也只有一个session对象。
    在这里插入图片描述

3.同根域名不同二级子域名下的项目实现Session 共享

同一个根域名,不同的二级子域名,比如北京和武汉的58同城域名:
武汉的58同城
在这里插入图片描述

3.1案例

添加域名映射: 找到C:\Windows\System32\drivers\etc路径下的hosts文件,在文件末尾加上:
127.0.0.1 p2p.myweb.com
127.0.0.1 shop.myweb.com

  • 通过测试发现这是无法实现两个服务器上session数据的共享
  • 原因:我们通过浏览器提供的开发人员工具可以发现,虽然这两个cookie 的路径(path)都设置为了“/”,但是这两个cookie的域名不一致,虽然我们已经加了Spring Session共享机制,但是后台服务器同样认为这是两个不同的会话(session),可以通过 Redis 客户端工具(Redis Destop Mananger)查看,先清空,然后访问,发现是维护了两个不同的session,所以不能实现共享,也就是说后台区分是否同一个 session 和路径和域名有关。
    在这里插入图片描述
    在这里插入图片描述
  • 解决方案:设置Cookie的域名为根域名 web.com,在 applicationContext-session.xml 文件中, 加如下配置:
    注意:域名要和 hosts 文件中配置的域名后面一样
<!--配置一个Cookie序列化规则对象 用于改变Cookie的存放规则 -->
    <bean id="defaultCookieSerializer" class="org.springframework.session.web.http.DefaultCookieSerializer">
        <!--指定SpringSession的SessionId存放在域名的根路径下,用于实现同域名不同项目的Session共享 -->
        <property name="cookiePath" value="/" />
        <!--指定SpringSession的SessionId存放在根域名下,用于实现同根域名不同二级子域名下的Session共享
            适合应用在Nginx的虚拟主机的多城市站点部署
         -->
        <property name="domainName" value="myweb.com"/>
    </bean>
  • 经过测试,发现可以实现session共享
    在这里插入图片描述
    在这里插入图片描述
    此时两次请求的Session ID都是存放在.myweb.com域名下
  • 12
    点赞
  • 104
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring Security是一个功能强大且灵活的身份验证和访问控制框架,用于保护基于Java的应用程序。它提供了一套全面的安全解决方案,可用于保护Web应用程序、RESTful API、方法级别的安全等。 Spring Security的核心原则是基于拦截器链(Filter Chain)的安全性,它通过一系列的过滤器(Filters)来处理不同的安全问题。这些过滤器可以在认证(Authentication)和授权(Authorization)过程中执行各种任务。 在Spring Security中,认证是指验证用户的身份,通常通过用户名和密码进行验证。授权是指根据用户的身份和角色来确定其是否有权访问特定资源或执行特定操作。 Spring Security提供了许多功能和扩展点,可以轻松地自定义和扩展以满足特定的需求。以下是一些Spring Security的主要功能: 1. 身份验证(Authentication):Spring Security支持多种身份验证方式,如基于数据库、LDAP、OAuth等。它还提供了记住我(Remember Me)和匿名访问等功能。 2. 授权(Authorization):Spring Security支持基于角色和权限的授权机制。可以配置细粒度的访问控制规则,以确保只有具有合适权限的用户可以访问受保护的资源。 3. 安全性注解(Security Annotations):Spring Security提供了一套注解,可以在方法级别上标记安全性要求。这些注解可以用于限制对特定方法的访问,并进行细粒度的授权控制。 4. CSRF保护(CSRF Protection):Spring Security提供了一种防止跨站请求伪造(CSRF)攻击的机制。它通过生成和验证CSRF令牌来确保只有合法的请求才能被处理。 5. Session管理(Session Management):Spring Security提供了对会话管理的支持,包括会话过期、并发控制和无效会话处理等功能。 6. 安全事件与日志(Security Events and Logging):Spring Security可以生成安全相关的事件,并提供了灵活的日志配置选项,以便记录和监视应用程序的安全状态。 以上只是Spring Security的一些主要功能,它还有很多其他特性和扩展点可用于满足各种安全需求。要详细了解Spring Security的使用和配置,可以参考官方文档或其他相关资源。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值