SpringSecurity 下 Session 使用

在之前的几章里面,我们分别做了快速入门、自定义表单登录、自定义手机登录。他们有一个共同点,就是目前我们与客户端之间的交互都依赖于 Session。那么本章我们就带大家来了解一下 SpringSecurity 下 Session 的使用与设置。

Session 是什么?

Session 中文意思为会议,在计算机中,尤其在网络应用中称为会话控制

Session直接翻译成中文比较困难,一般都译成时域。在计算机专业术语中,Session是指一个终端用户与交互系统进行通信的时间间隔,通常指从注册进入系统到注销退出系统之间所经过的时间。以及如果需要的话,可能还有一定的操作空间。

百度百科

为什么要使用 Session?

Http 协议本身是无状态的,多次连接之间的状态无法共享,服务端就判断是否是同一个用户操作的就比较麻烦。

而 Session 就是用来保存状态的,允许通过将对象存储在 Web 服务器内存中,在整个用户会话过程中进行共享。

Session 原理

浏览器第一次访问服务器时,服务端会生成 Session,然后同时为该 Session 生成一个唯一的 SessionId,然后将 SessionId 与 Session 以键值对的形式存储到内存中(Java 默认)。将 SessionId 以 Cookie 的方式返回给浏览器。浏览器下一次访问的时候就携带 SessionId 来访问,这样服务端通过查询就可以取出 Session 达到共享了。

在 SpringSecurity 里面的使用

单机 Session
  • Session 超时设置
    • 设置 Session 超时时间,在系统配置文件(application.properties/yml) 中配置

      server:session:timeout: 600 #单位为 Second,设置的时间低于 1 分钟,按 1 分钟处理
      
    • 设置 Session 超时/失效后继续访问处理,可以设置跳转页面,也可以设置跳转接口。前后端分离一般返回 Json,不分离可以引导页面跳转。两者都要兼容,可以跳转到自定义接口判断实际请求,进行处理。

      // 设置 Session 失效后访问跳转的页面
      http.sessionManagement().invalidSessionUrl("/session/invalid");
      
  • Session 并发控制
    • Session 最大数设置,限制系统中用户数量

      http.sessionManagement().maximumSessions(1)// 设置同时在线的最大 Session 数
      
    • 设置 Session 数量达到最大值时,是否阻止后面用户登录

      // 设置当 Session 数量达到最大数量时,阻止后面的登录
      http.sessionManagement().maxSessionsPreventsLogin(true);
      
    • 自定义设置 Session 数量达到最大时后续登录的处理策略,默认实现会将前面用户的 Session 置为失效

      // 设置 Session 并发登录时处理策略
      http.sessionManagement().expiredSessionStrategy(new DefaultExpiredSessionStrategy());
      
      /*** @author: hblolj* @Date: 2019/3/16 9:13* @Description: Session 并发登录时的处理策略* @Version:**/
      public class DefaultExpiredSessionStrategy implements SessionInformationExpiredStrategy{@Overridepublic void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {event.getResponse().setCharacterEncoding("UTF-8");event.getResponse().getWriter().write("并发登录!");}
      }
      
集群 Session(单机 Session 下的设置在集群下一样有效)

在单机 Session 下基本上只要处理好上面的问题就可以了,但是随着系统越来越大,单体应用可能满足不了我们的需求。如果我们对应用进行了集群,那么用户在每个应用上都会产生一个 Session,并且这些 Session 还不是共享的,就达不到 Session 使用的初衷了。

为了让 Session 可以共享,一般我们就会改变 Session 的存储方式,Session 默认存储在内存中,多个主机间就不方便共享。主流处理方案有:

  • 保存在数据库
  • 保存在 Redis 中
  • 利用 Servlet 容器来进行 Session 同步
  • 或者使用 Nginx 使用用户 ip 进行哈希处理,在负载均衡时,让用户每次访问同一个主机避免多 Session 问题

我们这里主要还是讨论 SpringSecurity 下集群 Session 的处理方案,其他扩展信息,大家感兴趣可以自行查询,或者留言讨论。

我们这里示例使用 Redis 作为 Session 存储方式,通过下列配置 Session 就会默认存储在 Redis 中了。关于 SpringBoot 下 Redis 的使用,不了解的可以查询资料使用,上手还是比较简单的。

  • 使用 Redis 作为 Session 的存储,通过配置文件指定存储方式。

    spring:session:store-type: redis #设置将 Session 存储在 Redis 中redis:host: redis 所在的主机port: 默认是 6379database: 选择使用的 databasepassword: your self passwordpool:max-wait: -1max-idle: 1max-active: 8min-idle: 0
    
  • 添加 Redis 依赖

    
    <dependency><groupId>org.springframework.bootgroupId><artifactId>spring-boot-starter-data-redisartifactId>
    dependency>
    
  • 添加 Spring-Session 依赖

    
    <dependency><groupId>org.springframework.sessiongroupId><artifactId>spring-sessionartifactId>
    dependency>
    
  • 除了 Redis,SpringBoot 还支持一下存储方式,大家可以自行扩展使用

    public enum StoreType {REDIS,MONGO,JDBC,HAZELCAST,HASH_MAP,NONE;private StoreType() {}
    }
    
退出登录

既然 Session 中共享用户多次请求的状态,那么如果我们要用户登出,就只要清空 Session 即可。那么在 SpringSecurity 下是怎样设置的呢?

  • 如何退出

    • 请求登出地址,默认为 /logout

    • 自定义登出地址

      http.logout().logoutUrl("/quit");// 默认是 logout
      
  • 退出处理原理 (访问退出地址,退出处理逻辑 SpringSecurity 有默认实现)

    • 使当前 Session 失效

      (HttpSession)session.invalidate();
      
    • 清除与当前用户先关的 remember-me 记录

      if (authentication != null) {this.tokenRepository.removeUserTokens(authentication.getName());
      }
      
    • 清空当前的 SecurityContext

      if (this.clearAuthentication) {SecurityContext context = SecurityContextHolder.getContext();context.setAuthentication((Authentication)null);
      }SecurityContextHolder.clearContext();
      
  • 与退出相关的配置

    • 自定义退出成功跳转页面或处理策略,同时设置只有 logoutSuccessHandler 会生效

      http.logout().logoutSuccessUrl("http://www.baidu.com") // 设置退出成功跳转的页面.logoutSuccessHandler(new DefaultLogoutSuccessHandler()) // 设置退出成功的处理策略
      
      /*** @author: hblolj* @Date: 2019/3/16 10:28* @Description:* @Version:**/
      @Slf4j
      public class DefaultLogoutSuccessHandler implements LogoutSuccessHandler{@Overridepublic void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {log.info("Logout Success!");}
      }
      
    • 设置退出时删除客户端 Cookie

      http.logout().deleteCookies("JSESSIONID") // 退出时删除客户端指定的 Cookie
      

OK,到了这里,基本上在 SpringSecurity 里面 Session 的常规设置与使用都介绍完了。大家如果有什么问题,欢迎在下面的留言区留言讨论。

实际上,在现在的开发中,单体 Web 应用可能还是以 Session 为主,但是如果要同时支持 App 的话, Session 就不是那么好用了,因为 Session 依赖 Cookie,虽然 App 访问时可以模拟浏览器设置 Cookie,但是契合度还是不如 Web,所以对于 App 或者集群环境下,现在主流使用基于 OAuth2 的 Token 作为验证。是不是以为我们下一章要讲 SpringSecurity 下 OAuth2 协议的集成与 Token 使用呢?哈哈,下一章我们计划带大家集成一下 SpringSecurity 下第三方登录,比如 QQ 快速登录、微信快速登录等(也依赖于 OAuth 协议)。至于集成 Token 认证还要往后几章哦!

To Be Continue!


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部