目录
前言
一、Java web设置session超时
二、session并发控制
三、退出/logout设置
本文是继SSM项目集成Spring Security 4.X版本(使用spring-security.xml 配置文件方式)_spring security4.x 会话管理配置文件版-CSDN博客https://blog.csdn.net/u011529483/article/details/135699004?spm=1001.2014.3001.5501文章之后的配置,继续实现了 session超时,单点登录-session并发控制,退出/logout 三项配置。
在配置过程中遇到了一些问题。正因如此才使我想要写文章记录。
java web应用设置session超时(默认是 30 分钟),也就是失效时间的方法有:
按优先执行权从高到底是:
1. 容器的配置中设置 如:tomcat的web.xml中设置
30
2. java项目的web.xml中设置(本文中采用了此种方式):
2
3. 通过java代码设置
HttpSession session = request.getSession();
session.setMaxInactiveInterval(120); //单位秒
Spring Security 中给我们提供了security:session-management标签进行session的配置管理,spring-security.xml 配置文件截图如下:
先来看看 invalid-session-url="/s_timeout.jsp" 配置的运行效果,手动设置session超时时间为 2 分钟,项目的web.xml文件中设置:
运行项目,登录成功后,等待2分钟后访问服务器。2分钟后session超时失效。
2 分钟后再次访问菜单查询跳转到了超时页面,说明我们的 invalid-session-url="/s_timeout.jsp" 配置生效了。
什么是session并发控制,就是同一个账号多处客户端同一时间段发起的请求,也就生成了多个session会话。session并发控制就是控制这些session会话的数量。现在我们将session会话数量设置为 1 ,即同时段同账号只能有一个用户登录成功,后面登录的挤掉前面登录的。spring-security.xml 配置如下:
max-sessions="1" 设置session并发数量为 1。
error-if-maximum-exceeded="false" 设置为false后面登录的挤掉前面登录的。设置为true表示前面登录的保留,后面登录的被拒绝。
要使以上设置生效还需要在项目的web.xml文件中添加监听
org.springframework.security.web.session.HttpSessionEventPublisher
网上很多都说了这两步配置,但是我配置后不生效。
后面我在网上查了原因,经过调试后实现了单点登录(同一个账号只能有一处登录在线)的效果。需要在 SysUser 实体类中(或自定义用户详情类中)重写equals和hashCode方法:
package com.wqbr.wqdemotwo.domain;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.*;
/**
* 系统用户,封装用户数据,实现 UserDetails 接口
* @author lv
* @date 2024年1月11日
*/
public class SysUser implements UserDetails {
private static final long serialVersionUID = 1L;
private String id;
private String username; //从UserDetails的重写方法中返回
private String password; //从UserDetails的重写方法中返回
private Date addtime;
private boolean accountnonexpired; //账户是否过期,从UserDetails的重写方法中返回
private boolean accountnonlocked; //账户是否锁定,从UserDetails的重写方法中返回
private boolean credentialsnonexpired; //密码是否过期,从UserDetails的重写方法中返回
private boolean enabled; //账户是否可用,从UserDetails的重写方法中返回
// 储存用户拥有的所有权限
private List authorities = new ArrayList<>(); //从UserDetails的重写方法中返回
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public Date getAddtime() {
return addtime;
}
public void setAddtime(Date addtime) {
this.addtime = addtime;
}
// 返回用户权限,上面声明了权限集合对象 authorities
@Override
public Collection extends GrantedAuthority> getAuthorities() {
return this.authorities;
}
public void setAuthorities(List authorities) {
this.authorities = authorities;
}
// 返回用户密码,上面声明了属性 password
@Override
public String getPassword() {
return password;
}
// 返回用户名,上面声明了属性 username
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return accountnonexpired;
}
public void setAccountnonexpired(boolean accountnonexpired) {
this.accountnonexpired = accountnonexpired;
}
@Override
public boolean isAccountNonLocked() {
return accountnonlocked;
}
public void setAccountnonlocked(boolean accountnonlocked) {
this.accountnonlocked = accountnonlocked;
}
@Override
public boolean isCredentialsNonExpired() {
return credentialsnonexpired;
}
public void setCredentialsnonexpired(boolean credentialsnonexpired) {
this.credentialsnonexpired = credentialsnonexpired;
}
@Override
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
/*重写equals和hashCode方法,因为如果是自定义的UserDetails 则需要重定义equal和hashcode。
另外Spring Security 中通过 SessionRegistryImpl 类来实现对会话信息的统一管理,而 SessionRegistryImpl 类中定义了
private final ConcurrentMap
为什么要重写这两个方法呢?因为自己动手创建用户实体类实现自定义用户详情验证,需要显式实现equals和hashCode方法。而我的用户实体类 SysUser 实现了 UserDetails接口。没有重写equals和hashCode方法,所以
导致这样配置的效果没有实现。另外Spring Security 中通过 SessionRegistryImpl 类来实现对会话信息的统一管理,而 SessionRegistryImpl 类中定义了 private final ConcurrentMap
现在来看看我们重写 equals 方法和 hashCode 方法后项目的运行效果:项目启动完毕后先在谷歌浏览器登录,登录成功后我访问了菜单请求如图:
说明登录成功,并顺利访问资源。且idea控制台打印的session信息:
登录成功,顺利请求到资源。且idea控制台打印的session信息:
可以看到360浏览器和谷歌浏览器访问的IDEA控制台打印出的session ID 不同,说明同一个用户发起了两次请求。此时再访问谷歌浏览器去请求一次资源得到如下结果:
继续刷新请求一次就重定向到会话超时页面:
此时360浏览器登录的用户是可以继续请求资源的。spring-security控制session并发数量,实现单点登录就实现了。
spring-security.xml 文件中的配置:
配置后运行项目,点击 退出 后 logout-success-url="/login" 重定向配置没有生效。查到原因:不能
spring-security.xml 完整的配置代码:
如此配置运行效果,点击退出后重定向到了登录页面。即logout-success-url="/login"配置生效。
退出页面代码:
<%-- --%>
退出系统
另外再看看退出时的 delete-cookies="JSESSIONID" 配置,如下idea控制台的截图可以看出,退出后重定向到退出的Controller请求时session ID重新生成了,说明浏览器cookies中的上一次JSESSIONID已经失效。
好了,小伙伴们这篇文章就到这里了,希望多留下你们的足迹,谢谢。