当前位置:  开发笔记 > 编程语言 > 正文

Spring Security会通过并发登录尝试来锁定用户

如何解决《SpringSecurity会通过并发登录尝试来锁定用户》经验,为你挑选了0个好方法。

我是安全新手,遇到了导致用户帐户被锁定的问题,只有应用程序重新启动才能修复它.

我有一个弹簧启动(1.3.0.BUILD-SNAPSHOT)与弹簧安全(4.0.2.RELEASE)应用程序,我试图控制并发会话策略,以便用户只能有一次登录.它正确检测来自其他浏览器的后续登录尝试并阻止它.但是,我注意到一些我似乎无法追查的奇怪行为:

用户可以在同一浏览器中对两个选项卡进行身份验证.我无法使用三个标签登录,但有两个标签.退出一个似乎注销两者.我看到cookie的值是一样的,所以我猜他们正在共享一个会话:

表1 JSESSIONID:DA7C3EF29D55297183AF5A9BEBEF191F &941135CEBFA92C3912ADDC1DE41CFE9A

表2 JSESSIONID:DA7C3EF29D55297183AF5A9BEBEF191F &48C17A19B2560EAB8EC3FDF51B179AAE

第二次登录尝试会显示以下日志消息,这些消息似乎表示第二次登录尝试(我通过Spring-Security源步进来验证:

o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /loginPage; Attributes: [permitAll]
 o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@754041c8: Principal: User [username=xxx@xxx.xx, password= ]; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@43458: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 4708D404F64EE758662B2B308F36FFAC; Granted Authorities: Owner
 o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@17527bbe, returned: 1
 o.s.s.w.a.i.FilterSecurityInterceptor    : Authorization successful
 o.s.s.w.a.i.FilterSecurityInterceptor    : RunAsManager did not change Authentication object
 o.s.security.web.FilterChainProxy        : /loginPage reached end of additional filter chain; proceeding with original chain
 org.apache.velocity                      : ResourceManager : unable to find resource 'loginPage.vm' in any resource loader.
 o.s.s.w.a.ExceptionTranslationFilter     : Chain processed normally
 s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed

当我使用两个选项卡登录然后注销时,用户帐户将被锁定并需要重新启动服务器.控制台中没有错误,db中的用户记录未更改.

这是我的安全配置:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

      @Autowired
      private CustomUserDetailsService customUserDetailsService;

      @Autowired
      private SessionRegistry sessionRegistry;

      @Autowired
      ServletContext servletContext;

      @Autowired
      private CustomLogoutHandler logoutHandler;

      @Autowired
      private MessageSource messageSource;


/**
 * Sets security configurations for the authentication manager
 */
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
                throws Exception {
    auth
                    .userDetailsService(customUserDetailsService)
                    .passwordEncoder(passwordEncoder());
    return;
}  
  protected void configure(HttpSecurity http) throws Exception {
        http
           .formLogin()
           .loginPage("/loginPage")
           .permitAll()
           .loginProcessingUrl("/login")
           .defaultSuccessUrl("/?tab=success")
           .and()
              .logout().addLogoutHandler(logoutHandler).logoutRequestMatcher( new AntPathRequestMatcher("/logout"))
              .deleteCookies("JSESSIONID")
               .invalidateHttpSession(true).permitAll().and().csrf()
           .and()  
              .sessionManagement().sessionAuthenticationStrategy(             concurrentSessionControlAuthenticationStrategy).sessionFixation().changeSessionId().maximumSessions(1)
              .maxSessionsPreventsLogin( true).expiredUrl("/login?expired" ).sessionRegistry(sessionRegistry )
          .and()
           .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
           .invalidSessionUrl("/")
           .and().authorizeRequests().anyRequest().authenticated();
        http.headers().contentTypeOptions();
        http.headers().xssProtection();
        http.headers().cacheControl();
        http.headers().httpStrictTransportSecurity();
        http.headers().frameOptions();
        servletContext.getSessionCookieConfig().setHttpOnly(true);
    }

  @Bean
  public ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlAuthenticationStrategy() {

      ConcurrentSessionControlAuthenticationStrategy strategy = new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry());
      strategy.setExceptionIfMaximumExceeded(true);
      strategy.setMessageSource(messageSource);

      return strategy;
  }

  // Work around https://jira.spring.io/browse/SEC-2855
  @Bean
  public SessionRegistry sessionRegistry() {
      SessionRegistry sessionRegistry = new SessionRegistryImpl();
      return sessionRegistry;
  }
}

我还有以下方法来处理检查用户:

@Entity
@Table(name = "USERS")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class,
                  property = "username")
public class User implements UserDetails {
...
 @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((username == null) ? 0 : username.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        User other = (User) obj;
        if (username == null) {
            if (other.username != null)
                return false;
        } else if (!username.equals(other.username))
            return false;
        return true;
    }
}

如何防止帐户锁定,或者至少如何以编程方式解锁?

编辑1/5/16 我在WebSecurityConfig中添加了以下内容:

 @Bean
    public static ServletListenerRegistrationBean httpSessionEventPublisher() {
        return new ServletListenerRegistrationBean(new HttpSessionEventPublisher());
    }

并删除:

servletContext.addListener(httpSessionEventPublisher())

但是当我在同一个浏览器上登录两次时,我仍然会看到这种行为 - 注销会锁定帐户,直到我重新启动.

推荐阅读
帆侮听我悄悄说星星
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有