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

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

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

实现

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

来源:http://ddrv.cn

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » Spring Boot + Spring Security 防止用户在多处同时登录(一个用户同时只能登录一次)及源码分析

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏