网上很多文章的实现方法写得比较复杂

这里介绍一个简单的方法。

实现

@Configuration

@EnableWebSecurity

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Override

protected void configure(HttpSecurity http) throws Exception {

http.csrf().disable()

.authorizeRequests()

.antMatchers("/user/**").access("hasRole('ADMIN') or hasRole('USER')")

.and().formLogin().permitAll();

//以下这句就可以控制单个用户只能创建一个session,也就只能在服务器登录一次

http.sessionManagement().maximumSessions(1).expiredUrl("/login");

}

原理

下面介绍下Spring Security的session数量控制的工作原理。

在org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy包下的onAuthentication方法(每次用户登录都会触发),会依据用户登录的authentication取出改用户在服务器的所有session,并计算该用户在服务器创建了多少个session,如果session多于设置的数量,会使用排序算法,得到最早的session,并将其设置为过期(删除)。

public void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {

List sessions = this.sessionRegistry.getAllSessions(authentication.getPrincipal(), false);

int sessionCount = sessions.size();

int allowedSessions = this.getMaximumSessionsForThisUser(authentication);

if (sessionCount >= allowedSessions) {

if (allowedSessions != -1) {

if (sessionCount == allowedSessions) {

HttpSession session = request.getSession(false);

if (session != null) {

Iterator var8 = sessions.iterator();

while(var8.hasNext()) {

SessionInformation si = (SessionInformation)var8.next();

if (si.getSessionId().equals(session.getId())) {

return;

}

}

}

}

this.allowableSessionsExceeded(sessions, allowedSessions, this.sessionRegistry);

}

}

}

protected void allowableSessionsExceeded(List sessions, int allowableSessions, SessionRegistry registry) throws SessionAuthenticationException {

if (!this.exceptionIfMaximumExceeded && sessions != null) {

SessionInformation leastRecentlyUsed = null;

Iterator var5 = sessions.iterator();

while(true) {

SessionInformation session;

do {

if (!var5.hasNext()) {

leastRecentlyUsed.expireNow();

return;

}

session = (SessionInformation)var5.next();

} while(leastRecentlyUsed != null && !session.getLastRequest().before(leastRecentlyUsed.getLastRequest()));

leastRecentlyUsed = session;

}

} else {

throw new SessionAuthenticationException(this.messages.getMessage("ConcurrentSessionControlAuthenticationStrategy.exceededAllowed", new Object[]{allowableSessions}, "Maximum sessions of {0} for this principal exceeded"));

}

}

Spring Security 是使用org.springframework.security.core.userdetails.User类作为用户登录凭据( Principal )的。该类中重写了equals()和hashCode(),使用username属性作为唯一凭据。

public boolean equals(Object rhs) {

return rhs instanceof User ? this.username.equals(((User)rhs).username) : false;

}

public int hashCode() {

return this.username.hashCode();

}

java中限制多人登录的_Spring Boot + Spring Security 防止用户在多处同时登录(一个用户同时只能登录一次)及源码分析...相关推荐

  1. Java程序员从笨鸟到菜鸟之(五十二)细谈Hibernate(三)Hibernate常用API详解及源码分析--csdn 曹胜欢...

    新接触一个框架的目的就是想利用这个框架来为我们做一些工作,或者是让他来简化我们的工作,利用这个框架无非就是要利用这个框架所给我们提供的API去操作我们的数据,所以利用一个框架的好坏很大一部分取决于你对 ...

  2. Java中ConcurrentHashMap底层实现原理(JDK1.8)源码分析2

    https://blog.csdn.net/programmer_at/article/details/79715177 https://blog.csdn.net/qq_41737716/categ ...

  3. Java中ArrayList源码分析

    一.简介 ArrayList是一个数组队列,相当于动态数组.每个ArrayList实例都有自己的容量,该容量至少和所存储数据的个数一样大小,在每次添加数据时,它会使用ensureCapacity()保 ...

  4. Java Review - 线程池中使用ThreadLocal不当导致的内存泄漏案例源码分析

    文章目录 概述 Why 内存泄露 ? 在线程池中使用ThreadLocal导致的内存泄漏 概述 ThreadLocal的基本使用我们就不赘述了,可以参考 每日一博 - ThreadLocal VS I ...

  5. java中Mark接口_JVM源码分析之Java对象头实现

    原标题:JVM源码分析之Java对象头实现 原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 "365篇原创计划"第十一篇. 今天呢!灯塔君跟大家讲: JVM源码分析之Ja ...

  6. 【Java】NIO中Selector的select方法源码分析

    该篇博客的有些内容和在之前介绍过了,在这里再次涉及到的就不详细说了,如果有不理解请看[Java]NIO中Channel的注册源码分析, [Java]NIO中Selector的创建源码分析 Select ...

  7. Java并发包中Semaphore的工作原理、源码分析及使用示例

    简介: 在多线程程序设计中有三个同步工具需要我们掌握,分别是Semaphore(信号量),countDownLatch(倒计数门闸锁),CyclicBarrier(可重用栅栏) 欢迎探讨,如有错误敬请 ...

  8. java usb摄像头_Android中多USB摄像头解决方案——UVCCamera源码分析(一)

    前言 前段时间捣鼓多USB摄像头的方案,一阵手忙脚乱算是勉强跑起来了.整个流程主要还是依赖于网上大神们封装好的库.之前想仔细分析一下整套底层实现,然而一直拖到现在--也没有完全看完,于是想着干脆分阶段 ...

  9. java将一个整数按字节输出_在java中的整数类型有四种,分别是 byte  short int long 其中byte只有一个字节 0或1,在此不详细讲解。其他的三种类型如下:1、...

    在java中的整数类型有四种,分别是 byte  short int long 其中byte只有一个字节 0或1,在此不详细讲解. 其他的三种类型如下: 1. 基本类型:short 二进制位数:16 ...

最新文章

  1. python读取excel日期内容读出来是数字-Python xlrd读取excel日期类型的2种方法
  2. 1.SQL数据定义语言(基础)
  3. 数据挖掘实践(金融风控)——task5:模型融合
  4. 算法-第四版-练习1.2.3解答
  5. html三级下拉栏插件,纯js超酷下拉框插件tastySelect
  6. 【数字信号处理】离散时间信号 ( 离散时间信号 与 连续时间信号 关系 | 序列表示法 | 列表法 | 函数表示法 | 图示法 )
  7. discuz 模板php,Discuz 模板语句分析及知识技巧
  8. Python+matplotlib绘制极坐标柱状图(南丁格尔玫瑰图)
  9. python 回归方程及回归系数的显著性检验_使用Excel和python来做回归分析
  10. OPA1611AIDR IC AUDIO 1 CIRCUIT 8SOIC
  11. strawberry perl环境安装介绍
  12. 洛谷刷题C语言:闰年判断、Apples、洛谷团队系统、肥胖问题、三位数排序
  13. 【计算机网络-1】为什么学习计算机网络
  14. java单根结构_java“单根继承结构”
  15. CF375C Circling Round Treasures(BFS+DP)
  16. FND_GLOBAL.CONC_REQUEST_ID = -1
  17. 杰西·李佛摩尔的股市存亡战
  18. 20170327 阁下何不随风起
  19. 大型企业如何搭建自有协同办公平台?
  20. 如何用标签软件自动打印并记录流水号?

热门文章

  1. 清华大学MBA在职班第一学年第二学期课表
  2. Hub与Switch的帧的广播细节
  3. TensorRT C++ API用法
  4. Tensorflow 中添加正则化项
  5. Extjs利用iframe无弹窗导出下载文件
  6. 基于ipv6的数据包分析(GNS3)
  7. Codeforces Round #476 (Div. 2)
  8. jackson 进行json与java对象转换 之二
  9. 程序员常见的健康问题
  10. 6Linux 终端命令格式