spring security 关于 http.sessionManagement().maximumSessions(1);的探究
1.前言
spring security 支持对session的管理 ,
http.sessionManagement().maximumSessions(1);的意思的开启session管理,session并发最多一个,超出后,
旧的session被注销,新的会注册,这种操作称为缺省实现 。
session缺省实现原理是将session记录在内存map中,因此不能用于集群环境中,会导致服务器1中记录的信息和服务器2记录的信息并不相同;
解决的方案是使用spring session ,session存在redis里面作为共享信息【具体以后的随笔会详细讲解,这里不多解释】
2.操作
使用上一随笔做的spring security前后端分离跨域的工程做测试
security完整配置


package com.example.securityqh5601.config.security; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; //这个加不加无所谓
//@Configuration
//开启security自定义配置
@EnableWebSecurity
//开启 Controller层的访问方法权限,与注解@PreAuthorize("hasRole('ROLE_admin')")配合,会拦截注解了@PreAuthrize注解的配置
// 想要@PreAuthorize正确执行 ,权限关键字必须带前缀 ROLE_ ,后面的部分可以随便写!!!!靠,琢磨了4小时了 ,终于找到原因了
@EnableGlobalMethodSecurity(prePostEnabled = true)
//
public class WebSecurityConfig2 extends WebSecurityConfigurerAdapter { //实例自定义登录校验接口 【内部有 数据库查询】
@Autowired
private DbUserDetailsService2 dbUserDetailsService; /**
* 忽略过滤的静态文件路径
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(
"/js/**/*.js",
"/css/**/*.css",
"/img/**",
"/html/**/*.html"
);
} /**
* 全局的跨域配置
*/
@Bean
public WebMvcConfigurer WebMvcConfigurer() {
return new WebMvcConfigurer() {
public void addCorsMappings(CorsRegistry corsRegistry) {
//仅仅让/login可以跨域
corsRegistry.addMapping("/login").allowCredentials(true).allowedHeaders("*");
//仅仅让/logout可以跨域
corsRegistry.addMapping("/logout").allowCredentials(true).allowedHeaders("*");
//允许所有接口可以跨域访问
//corsRegistry.addMapping("/**").allowCredentials(true).allowedHeaders("*"); }
}; } //拦截规则设置
@Override
protected void configure(HttpSecurity http) throws Exception { //开启授权认证
//开启跨域共享,关闭同源策略【允许跨域】
http.cors()
//跨域伪造请求=无效,
.and().csrf().disable(); //配置路径拦截规则
http.authorizeRequests()
// 只要有 "user","admin"任意最少一个权限即可访问路径"/user/**"的所有接口
// .antMatchers("/user/**").hasAnyAuthority("ROLE_user", "ROLE_admin")
// //只有权限"admin"才可以访问"/admin/**"所有路径 和 接口 "/vip"
// .antMatchers("/admin/**", "/vip").hasAuthority("ROLE_admin")
//所有请求都需要验证,必须要放在antMatchers路径拦截之后,不然拦截失效
.anyRequest().authenticated();
// //路径拦截权限的名称必须与权限列表注册的一样,经过测试,方法级别的注解权限需要ROLE_前缀 ,因此,
// 路径拦截权限的名称、注解权限名称、数据库存储的权限名称都要加ROLE_前缀最好,避免出现错误,
// 如果数据库的权限名称不加ROLE_前缀,那么在注册权限列表的时候记得拼接ROLE_前缀 //登录配置
http.formLogin()
//登录名参数
.usernameParameter("username")
//密码参数
.passwordParameter("password")
//post登录访问路径
.loginProcessingUrl("/login"); //登录结果处理
http.formLogin()
//登录成功
.successHandler(new CustomAuthenticationSuccessHandler()) //--0
//登录失败
.failureHandler(new CustomAuthenticationFailureHandler()); //--0 //登录退出处理
http.logout()
////post登出访问路径
.logoutUrl("/logout")
//成功退出处理
.logoutSuccessHandler(new CustomLogoutSuccessHandler()) //--0
//清除认证信息
.clearAuthentication(true).permitAll(); //异常抛出处理
http.exceptionHandling().authenticationEntryPoint(new CustomAuthenticationEntryPoint()) //-- 401
//访问拒绝处理【无权】
.accessDeniedHandler(new CustomAccessDeniedHandler()); //--2 //开启cookie自动登录
http.rememberMe()
//自动登录成功处理//todo
// .authenticationSuccessHandler(new ....)
//密钥
.key("unique-and-secret")
//cookie名
.rememberMeCookieName("remember-me-cookie-name")
//生命周期,单位毫秒
.tokenValiditySeconds(24 * 60 * 60); //session并发管理 ,原理是其缺省实现是将session记录在内存map中,因此不能用于集群环境中,服务器1中记录的信息和服务器2记录的信息并不相同;
//
// Session的并发控制,这里设为最多一个,只允许一个用户登录,如果同一个账户两次登录,那么第一个账户将被踢下线
http.sessionManagement().maximumSessions(1);
//当一个用户已经认证过了,在另外一个地方重新进行登录认证,spring security可以阻止其再次登录认证,从而保持原来的会话可用性
//存在一个问题,当用户登陆后,没有退出直接关闭浏览器,则再次打开浏览器时,此时浏览器的session若被删除的话,用户只能等到服务器的session过期后,才能再次登录。
// http.sessionManagement().maximumSessions(1).maxSessionsPreventsLogin(true);
//默认是开通session fixation防护的.因此可以不写,防护的原理为,每当用户认证过后,就会重新生成一个新的session,并抛弃旧的session
// http.sessionManagement().sessionFixation().migrateSession(); //解决不允许显示在iframe的问题
// http.headers().frameOptions().disable(); } /**
* 添加 UserDetailsService, 实现自定义登录校验,数据库查询
*/
@Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
//注入用户信息,每次登录都会来这查询一次信息,因此不建议每次都向mysql查询,应该使用redis
builder.userDetailsService(dbUserDetailsService)
//密码加密方式
.passwordEncoder(passwordEncoder());
} /**
* BCryptPasswordEncoder相关知识:
* 用户表的密码通常使用MD5等不可逆算法加密后存储,为防止彩虹表破解更会先使用一个特定的字符串(如域名)加密,然后再使用一个随机的salt(盐值)加密。
* 特定字符串是程序代码中固定的,salt是每个密码单独随机,一般给用户表加一个字段单独存储,比较麻烦。
* BCrypt算法将salt随机并混入最终加密后的密码,验证时也无需单独提供之前的salt,从而无需单独处理salt问题。
*/
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
} //参考 博文原址
//https://www.dazhuanlan.com/2019/10/01/5d92e281abbc4/
//https://www.cnblogs.com/guos/archive/2019/10/02/11617243.html
//https://blog.csdn.net/icarusliu/article/details/78722384
//真想哭
其他的这里没必要再写一次了
不过前端文件我需要特别改一下
我i什么这样做呢?
因为: // 当session并发上线被踢下线时,xhr会返回信息
//{"readyState":4,"responseText":"This session has been expired
// (possibly due to multiple concurrent logins being attempted
// as the same user).","status":200,"statusText":"parsererror"}
3.测试
启动工程
(1)使用两个不同的浏览器分别访问网址 ,分别设为A 和 B 好区分
账户=cen ,密码 = 11
A登录,显示登录成功
(2)A点击获取认证信息,可以获取
(3)此时,B也登录上面的账户,此时B显示登录成功,而A没变化 ,那是因为没有socket 协议,服务器无法主动向前端传数据
(4)现在B点发送信息,成功获取处理结果,不影响业务
(5)现在,A点击获取认证信息,提示 “被强制下线,已在另一台设备登录”
显然,B把A挤下线了 !!!!
测试成功,撒花!!!!
spring security 关于 http.sessionManagement().maximumSessions(1);的探究的更多相关文章
- spring security之httpSecurity使用示例
如果在HttpSecurity中配置需要authenticate(),则如果没有登陆,或没有相关权限,则会无法访问 2017-01-02 23:39:32.027 DEBUG 10396 --- [n ...
- 【Spring】关于Boot应用中集成Spring Security你必须了解的那些事
Spring Security Spring Security是Spring社区的一个顶级项目,也是Spring Boot官方推荐使用的Security框架.除了常规的Authentication和A ...
- Spring Boot+Spring Security:获取用户信息和session并发控制
说明 (1)JDK版本:1.8(2)Spring Boot 2.0.6(3)Spring Security 5.0.9(4)Spring Data JPA 2.0.11.RELEASE(5)hiber ...
- Spring Security 5.0.x 参考手册 【翻译自官方GIT-2018.06.12】
源码请移步至:https://github.com/aquariuspj/spring-security/tree/translator/docs/manual/src/docs/asciidoc 版 ...
- Spring Security 之集群Session配置
1. 新建Maven项目 cluster-session 2. pom.xml <project xmlns="http://maven.apache.org/POM/4.0. ...
- Spring Security 之Session管理配置
废话不多说,直接上代码.示例如下: 1. 新建Maven项目 session 2. pom.xml <project xmlns="http://maven.apache.o ...
- 使用Spring Security控制会话
1.概述 在本文中,我们将说明Spring Security如何允许我们控制HTTP会话.此控件的范围从会话超时到启用并发会话和其他高级安全配置. 2.会话何时创建? 我们可以准确控制会话何时创建以及 ...
- 关于Boot应用中集成Spring Security你必须了解的那些事
Spring Security Spring Security是Spring社区的一个顶级项目,也是Spring Boot官方推荐使用的Security框架.除了常规的Authentication和A ...
- spring boot系列--spring security (基于数据库)登录和权限控制
先说一下AuthConfig.java Spring Security的主要配置文件之一 AuthConfig 1 @Configuration 2 @EnableWebSecurity 3 publ ...
随机推荐
- 如何利用EL表达式获取list,map,对象等值
<%@ page import="com.hopetesting.domain.User" %><%@ page import="java.util.* ...
- 使用JDBCTemplate执行DQL/DML语句
package cn.itcast.datasource.jdbctemplate;import cn.itcast.domain.User;import cn.itcast.utils.JDBCUt ...
- 如何用three.js实现数字孪生、3D工厂、3D工业园区、智慧制造、智慧工业、智慧工厂-第十课
文章前,先聊点啥吧. 最近元宇宙炒的挺火热,在所有人都争相定义元宇宙的时候,资本就开始着手入场了.当定义明确,全民皆懂之后,风口也就过去了. 前两天看到新闻,新世界CEO宣布购入最大的数字地块,这块虚 ...
- 使用 scipy.fft 进行Fourier Transform:Python 信号处理
摘要:Fourier transform 是一个强大的概念,用于各种领域,从纯数学到音频工程甚至金融. 本文分享自华为云社区<使用 scipy.fft 进行Fourier Transform:P ...
- HGAME2021 week2 pwn writeup
week2一共有4道pwn题 killerqueen 有格式化字符串漏洞,题不算难,但是故事情节真实让人摸不着头脑,但是仔细分析分析,理清楚逻辑就可以做了. 第一次choose1的时候,可以输入0,泄 ...
- [BUUCTF]REVERSE——reverse2
reverse2 附件 例行检查,64位目标 64位ida载入,首先shift+f12检索程序里的字符串 得到了"this is the right flag!" 的提示字符串,还 ...
- JAVA将文件转换成byte数组(byte[])
/** * 将文件转换成byte数组 * @param filePath 文件File类 通过new File(文件路径) * @return byte数组 */ public static byte ...
- Elasticsearch删除所有数据
使用post请求 POST http://localhost:9200/索引/标签/_delete_by_query?pretty { "query": { "match ...
- iOS越狱插件源查找及避免插件劫持
1.关于 iOS越狱插件源查找地址:https://www.ios-repo-updates.com/ 2.注意 不要使用不可靠的第三方源,其可能存在劫持,而你却茫然不知. 使用上面的网站查找你需要的 ...
- 【LeetCode】283. Move Zeroes 解题报告(Java & Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 方法一:首尾指针 方法二:头部双指针+双循环 方法三 ...