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);的探究的更多相关文章

  1. spring security之httpSecurity使用示例

    如果在HttpSecurity中配置需要authenticate(),则如果没有登陆,或没有相关权限,则会无法访问 2017-01-02 23:39:32.027 DEBUG 10396 --- [n ...

  2. 【Spring】关于Boot应用中集成Spring Security你必须了解的那些事

    Spring Security Spring Security是Spring社区的一个顶级项目,也是Spring Boot官方推荐使用的Security框架.除了常规的Authentication和A ...

  3. 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 ...

  4. Spring Security 5.0.x 参考手册 【翻译自官方GIT-2018.06.12】

    源码请移步至:https://github.com/aquariuspj/spring-security/tree/translator/docs/manual/src/docs/asciidoc 版 ...

  5. Spring Security 之集群Session配置

    1.   新建Maven项目 cluster-session 2.   pom.xml <project xmlns="http://maven.apache.org/POM/4.0. ...

  6. Spring Security 之Session管理配置

    废话不多说,直接上代码.示例如下: 1.   新建Maven项目  session 2.   pom.xml <project xmlns="http://maven.apache.o ...

  7. 使用Spring Security控制会话

    1.概述 在本文中,我们将说明Spring Security如何允许我们控制HTTP会话.此控件的范围从会话超时到启用并发会话和其他高级安全配置. 2.会话何时创建? 我们可以准确控制会话何时创建以及 ...

  8. 关于Boot应用中集成Spring Security你必须了解的那些事

    Spring Security Spring Security是Spring社区的一个顶级项目,也是Spring Boot官方推荐使用的Security框架.除了常规的Authentication和A ...

  9. spring boot系列--spring security (基于数据库)登录和权限控制

    先说一下AuthConfig.java Spring Security的主要配置文件之一 AuthConfig 1 @Configuration 2 @EnableWebSecurity 3 publ ...

随机推荐

  1. 🔥🔥🔥Flutter 字节跳动穿山甲广告插件发布 - FlutterAds

    前言 Flutter 已成为目前最流行的跨平台框架之一,在近期的几个大版本的发布中都提到了 Flutter 版本 Google 广告插件 [google_mobile_ads] .对于"出海 ...

  2. Nginx中指令

    Rewrite模块 1 return指令 Syntax: return code [text]; return code URL; return URL; Default: - Context: se ...

  3. uniapp-uView表单中如何添加日期控件?

    环境:uniapp,uview-ui,Picker 选择器, 本次我们用uview中的Picker 选择器来写一个日期功能 此选择器有四种弹出模式 一是时间模式,可以配置年,日,月,时,分,秒参数二是 ...

  4. SpringMVC 入门、请求、响应

    目录 SpringMVC 概述 SSM 简介 MVC 简介 SpringMVC 简介 入门案例 Spring 技术架构 SpringMVC 基础配置 常规配置 Controller 加载控制 静态资源 ...

  5. Django查询结果以时间正序或者倒序排列

    正序 time1 = details.objects.all().order_by('time') 倒序 time2 = details.objects.all().order_by('-time')

  6. CF355B Vasya and Public Transport 题解

    Content 小 \(A\) 要乘坐交通工具,其中公交车的辆数是 \(n\),第 \(i\) 辆公交车的编号为 \(i\),乘坐次数为 \(a_i\):手推车的辆数是 \(m\),每辆手推车的编号为 ...

  7. LuoguP5139 z小f的函数 题解

    Content 给定 \(T\) 个二次函数 \(y=ax^2+bx+c\),有若干次操作,有一个操作编号 \(p\),保证仅为以下这五种: 操作 \(1\):给定 \(k\),将函数图像向上移动 \ ...

  8. 树莓派CM4 wifi频繁断开连接

    CM4核心板上自带的wifi模块连接上华为/小米的路由器5G热点以后,会频繁断开连接,断开连接前使用 iw dev 查看wifi信息如下: phy#0 Unnamed/non-netdev inter ...

  9. 云主机tracert外网无返回需在安全组入方向加ICMP Time Exceeded TTLexpired in transit

  10. 访问struts2的action页面出现白板问题

    访问struts2的action页面出现白板问题 故需要设置拦截此action的拦截栈, <bean id="authenticationInterceptor" class ...