本篇博客介绍spring-security中会话的管理以及安全退出的操作
单机值得是单服务器,单服务器的session管理比较容易
指定session的超时时间,其实这个不限于单机的session管理,在集群的session管理下,配置的session超时时间依旧有效。配置超时时间,我们只需要在配置文件中配置如下属性即可
#session超时时间,单位秒
server.session.timeout=600
需要说明的是,如果使用的是springboot内嵌的tomcat启动系统,则在springboot的TomcatEmbeddedServletContainerFactory
类中,这个过时时间最低会被设置为60秒,因此如果使用springboot内嵌的tomcat启动应用,则session最少的过期时间为1分钟。
针对session过期的处理,在配置中加上如下配置即可
http.and()
.sessionManagement()
.invalidSessionUrl("/authentication/sessiontimeout")//这里配置session失效的url
invalidSessionUrl指定session失效以后跳转的目标url。
session的并发控制是指,同一个用户在服务器端只能存在的会话个数,如果指定为1,则表示客户在服务器中只能存在一个会话,对于客户来说,也只能在一台设备上登录,不能在多台设备上登录,如果在未知设备上登录,则会根据session并发控制的相关策略进行处理。
http.and()
.sessionManagement()
.invalidSessionUrl("/authentication/sessiontimeout")//这里配置session失效的url
.maximumSessions(1)//最大会话数
.expiredSessionStrategy(new SelfExpireSessionStrategy())//自定义的淘汰会话策略
.and()
自定义的会话淘汰策略
/**
* autor:liman
* createtime:2021/7/18
* comment:自定义的会话淘汰策略
* 实现SessionInformationExpiredStrategy接口,这个接口有一个SessionInformationExpiredEvent属性
* 这个属性记录了最新的登录请求响应的所有数据。
*/
public class SelfExpireSessionStrategy implements SessionInformationExpiredStrategy {
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException, ServletException {
//这里可以记录新的登录信息
event.getResponse().setContentType("application/json;charset=UTF-8");
event.getResponse().getWriter().write("在新的设备上登录了");
}
}
如果会话已经存在,想阻止登录,则加一行配置即可
http.and()
.sessionManagement()
.invalidSessionUrl("/authentication/sessiontimeout")//这里配置session失效的url
.maximumSessions(1)//最大会话数
.expiredSessionStrategy(new SelfExpireSessionStrategy())//自定义的淘汰会话策略
.maxSessionsPreventsLogin(true)//如果会话存在,则阻止后续登录
.and()
针对集群下的session共享,这里不解释为啥需要session共享。只是记录解决方案。这里我们使用spring-session来完成集群session共享。
需要在pom中引入spring-session(版本号根据自己项目特性进行指定)
<dependency>
<groupId>org.springframework.sessiongroupId>
<artifactId>spring-sessionartifactId>
dependency>
其实spring-session支持很多持久化session的方式,这里我们以Redis为例进行总结,我们需要做的并不多,因为本身也不复杂。之后我们需要在配置文件中指定session持久化方式即可
#集群session存储方式
spring.session.store-type=REDIS
我们不需要编写其他代码,如果想自定义session过期时间或者自定义session的命名空间,则可以在启动类上加如下注解
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 60*10,redisNamespace = "self#security#session")
登录之后,进入到Redis,可以看到存放的会话信息
图中圈出的就是sessionid
这个比较简单,只需要在配置中指定自定义的退出逻辑即可,其余的交给spring-security指定帮我们完成
http.and()
.logout()
.logoutUrl("/logout")//针对安全配置的请求
.logoutSuccessHandler(new SelfLogoutSuccessHandler())//这个与下面的logoutSuccessUrl互斥
// .logoutSuccessUrl("/demo-logout.html")
// .deleteCookies("JSESSIONID")//删除cookid,如果前后端分离的,则不需要处理
自定义的登录处理
/**
* autor:liman
* createtime:2021/7/18
* comment: 自定义退出登录的处理
*/
@Slf4j
public class SelfLogoutSuccessHandler implements LogoutSuccessHandler {
private ObjectMapper objectMapper = new ObjectMapper();
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//如果没有配置退出页面
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(objectMapper.writeValueAsString(new BaseResponse(StatusCode.Success)));
log.info("退出登录成功");
}
}
上述是前后端分离的退出操作,如果不想前后端分离,则可以指定logoutSuccessUrl,在退出后跳转至指定的页面即可。
总结一下会话和安全退出的功能