Spring Boot + Spring Security 防止用户在多处同时登录(一个用户同时只能登录一次)及源码分析

编程知识 更新时间:2023-05-02 02:42:58

网上很多文章的实现方法写得比较复杂
这里介绍一个简单的方法。

实现

@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<SessionInformation> 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<SessionInformation> 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();
    }

更多推荐

Spring Boot + Spring Security 防止用户在多处同时登录(一个用户同时只能登录一次)及源码分析

本文发布于:2023-04-25 08:14:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/71d7287f734c0ac3a516018918f07d83.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:用户   多处   源码   Spring   Boot

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!

  • 102605文章数
  • 26164阅读数
  • 0评论数