在之前的几章里面,我们分别做了快速入门、自定义表单登录、自定义手机登录。他们有一个共同点,就是目前我们与客户端之间的交互都依赖于 Session。那么本章我们就带大家来了解一下 SpringSecurity 下 Session 的使用与设置。
Session 中文意思为会议,在计算机中,尤其在网络应用中称为会话控制。
Http 协议本身是无状态的,多次连接之间的状态无法共享,服务端就判断是否是同一个用户操作的就比较麻烦。
而 Session 就是用来保存状态的,允许通过将对象存储在 Web 服务器内存中,在整个用户会话过程中进行共享。
浏览器第一次访问服务器时,服务端会生成 Session,然后同时为该 Session 生成一个唯一的 SessionId,然后将 SessionId 与 Session 以键值对的形式存储到内存中(Java 默认)。将 SessionId 以 Cookie 的方式返回给浏览器。浏览器下一次访问的时候就携带 SessionId 来访问,这样服务端通过查询就可以取出 Session 达到共享了。
设置 Session 超时时间,在系统配置文件(application.properties/yml) 中配置
server:
session:
timeout: 600 #单位为 Second,设置的时间低于 1 分钟,按 1 分钟处理
设置 Session 超时/失效后继续访问处理,可以设置跳转页面,也可以设置跳转接口。前后端分离一般返回 Json,不分离可以引导页面跳转。两者都要兼容,可以跳转到自定义接口判断实际请求,进行处理。
// 设置 Session 失效后访问跳转的页面
http.sessionManagement().invalidSessionUrl("/session/invalid");
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{
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
event.getResponse().setCharacterEncoding("UTF-8");
event.getResponse().getWriter().write("并发登录!");
}
}
在单机 Session 下基本上只要处理好上面的问题就可以了,但是随着系统越来越大,单体应用可能满足不了我们的需求。如果我们对应用进行了集群,那么用户在每个应用上都会产生一个 Session,并且这些 Session 还不是共享的,就达不到 Session 使用的初衷了。
为了让 Session 可以共享,一般我们就会改变 Session 的存储方式,Session 默认存储在内存中,多个主机间就不方便共享。主流处理方案有:
我们这里主要还是讨论 SpringSecurity 下集群 Session 的处理方案,其他扩展信息,大家感兴趣可以自行查询,或者留言讨论。
我们这里示例使用 Redis 作为 Session 存储方式,通过下列配置 Session 就会默认存储在 Redis 中了。关于 SpringBoot 下 Redis 的使用,不了解的可以查询资料使用,上手还是比较简单的。
使用 Redis 作为 Session 的存储,通过配置文件指定存储方式。
spring:
session:
store-type: redis #设置将 Session 存储在 Redis 中
redis:
host: redis 所在的主机
port: 默认是 6379
database: 选择使用的 database
password: your self password
pool:
max-wait: -1
max-idle: 1
max-active: 8
min-idle: 0
添加 Redis 依赖
<!-- SpringBoot 版本 1.5.19.RELEASE-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
添加 Spring-Session 依赖
<!-- SpringBoot 版本 1.5.19.RELEASE-->
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session</artifactId>
</dependency>
除了 Redis,SpringBoot 还支持一下存储方式,大家可以自行扩展使用
public enum StoreType {
REDIS,
MONGO,
JDBC,
HAZELCAST,
HASH_MAP,
NONE;
private StoreType() {
}
}
既然 Session 享用户多次请求的状态,那么如果我们要用户登出,就只要清空 Session 即可。那么在 SpringSecurity 下是怎样设置的呢?
如何退出
http.logout().logoutUrl("/quit");// 默认是 logout
使当前 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{
@Override
public 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!
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- niushuan.com 版权所有 赣ICP备2024042780号-2
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务