首页 > 编程语言 > 详细

SpringSecurity之sessionManagement设置maximumSessions无效

时间:2021-08-09 23:07:14      阅读:163      评论:0      收藏:0      [点我收藏+]

maximumSessions配置session最大的数量,可以实现常见的,一个账号同一时间只能在一台设备登录,类似qq,实现方式有两种,一种是后登录的人会把先登录的人挤下去,还有一种一旦账号被登录,其他人就不能在登陆了,具体使用那种还是得看业务

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .successHandler((req,resp,authentication) -> {
                    Object principal = authentication.getPrincipal();
                    PrintWriter out = resp.getWriter();
                    out.println(JSON.toJSON(principal));
                    out.flush();
                    out.close();
                })
                .and()
                .authorizeRequests()
                .antMatchers("/admin/**").hasRole("admin")
                .antMatchers("/user/**").hasRole("user")
                .anyRequest().authenticated()
                .and()
                .csrf().disable()
                .sessionManagement()
                .maximumSessions(1)
                .maxSessionsPreventsLogin(true); // 配置为true就是一旦用户登录,则不允许其他人登录,使用这个需要配置一个Bean(HttpSessionEventPublisher)

    }
   @Bean
    HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }
  

分析:如题所示,在使用Security的sessionManagement配置maximumSessions无效,这是因为Spring Security 中通过 SessionRegistryImpl 类来实现对会话信息的统一管理,看看这个类的源码

public class SessionRegistryImpl implements SessionRegistry,
  ApplicationListener<SessionDestroyedEvent> {
 /** <principal:Object,SessionIdSet> */
 private final ConcurrentMap<Object, Set<String>> principals;
 /** <sessionId:Object,SessionInformation> */
 private final Map<String, SessionInformation> sessionIds;
 public void registerNewSession(String sessionId, Object principal) {
  if (getSessionInformation(sessionId) != null) {
   removeSessionInformation(sessionId);
  }
  sessionIds.put(sessionId,
    new SessionInformation(principal, sessionId, new Date()));

  principals.compute(principal, (key, sessionsUsedByPrincipal) -> {
   if (sessionsUsedByPrincipal == null) {
    sessionsUsedByPrincipal = new CopyOnWriteArraySet<>();
   }
   sessionsUsedByPrincipal.add(sessionId);
   return sessionsUsedByPrincipal;
  });
 }
 public void removeSessionInformation(String sessionId) {
  SessionInformation info = getSessionInformation(sessionId);
  if (info == null) {
   return;
  }
  sessionIds.remove(sessionId);
  principals.computeIfPresent(info.getPrincipal(), (key, sessionsUsedByPrincipal) -> {
   sessionsUsedByPrincipal.remove(sessionId);
   if (sessionsUsedByPrincipal.isEmpty()) {
    sessionsUsedByPrincipal = null;
   }
   return sessionsUsedByPrincipal;
  });
 }

}

1.首先一上来声明了一个 principals 对象,这是一个支持并发访问的 map 集合,集合的 key 就是用户的主体(principal),正常来说,用户的 principal 其实就是用户对象
2.如有新的 session 需要添加,就在 registerNewSession 方法中进行添加,具体是调用 principals.compute 方法进行添加,key 就是 principal。
3.如果用户注销登录,sessionid 需要移除,相关操作在 removeSessionInformation 方法中完成,具体也是调用 principals.computeIfPresent 方法,这些关于集合的基本操作我就不再赘述了。
其中的ConcurrentMap 集合的 key 是 principal 对象,用对象做 key,一定要重写 equals 方法和 hashCode 方法,否则第一次存完数据,下次就找不到了。

SpringSecurity之sessionManagement设置maximumSessions无效

原文:https://www.cnblogs.com/cyoking/p/15120209.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!