使用自定义UsernamePasswordAuthenticationFilter进行Spring安全并发控制

时间:2017-06-08 10:14:05

标签: spring-security session-management

根据新要求,我创建了自定义UsernamePasswordAuthenticationFilter以从登录页面捕获其他参数。正如所料,我的配置工作正常。我能够在过滤器中检索其他参数并保存到会话中。但是在将自定义过滤器添加到config后,会话管理无效。以前我通过将最大会话值设置为1来允许每个用户只有一个会话。它现在不工作,应用程序允许同一用户多次登录。我确定只有在将自定义UsernamePasswordAuthenticationFilter集成到我的配置后才会发生这种情况。下面是我的春季安全配置。

http.formLogin()
            .loginPage("/login.html")
            .loginProcessingUrl("/login.html")
            .usernameParameter("username")
            .passwordParameter("password")
            .and()
        .logout()
            .logoutSuccessUrl("/login.html")
            .logoutRequestMatcher(new AntPathRequestMatcher("/logout.html"))
            .invalidateHttpSession(true)
            .deleteCookies("JSESSIONID")
            .and()
        .sessionManagement()
            .maximumSessions(1)
            .expiredUrl("/multiplesessions.html")
            .sessionRegistry(getSessionRegistry());
        http.addFilterBefore(customUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);


@Bean
public SessionRegistry getSessionRegistry() {
    return new SessionRegistryImpl();
}
@Autowired
    public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {

    DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    provider.setUserDetailsService(dsnyUserDetailsService);
    provider.setPasswordEncoder(passwordEncoder());
    auth.authenticationProvider(provider);
}

@Bean
public PasswordEncoder passwordEncoder() {
    return new StandardPasswordEncoder();
}

@Bean(name = "myAuthenticationManager")
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}

@Bean
DsnyUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter() throws Exception {
    DsnyUsernamePasswordAuthenticationFilter customUsernamePasswordAuthenticationFilter = new DsnyUsernamePasswordAuthenticationFilter();
    customUsernamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManagerBean());
    customUsernamePasswordAuthenticationFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login.html", "POST"));

    return customUsernamePasswordAuthenticationFilter;
}

我在这里错过任何东西吗?

1 个答案:

答案 0 :(得分:2)

我通过添加自定义ConcurrentSessionFilter解决了这个问题。如果有人愿意,这是代码。

    http.sessionManagement().sessionAuthenticationStrategy(concurrentSession());
    http.addFilterBefore(concurrentSessionFilter(), ConcurrentSessionFilter.class);

   @Bean
   public CompositeSessionAuthenticationStrategy concurrentSession() {

            ConcurrentSessionControlAuthenticationStrategy concurrentAuthenticationStrategy = new ConcurrentSessionControlAuthenticationStrategy(getSessionRegistry());
            concurrentAuthenticationStrategy.setMaximumSessions(1);
            //concurrentAuthenticationStrategy.setExceptionIfMaximumExceeded(true);
            List<SessionAuthenticationStrategy> delegateStrategies = new ArrayList<SessionAuthenticationStrategy>();
            delegateStrategies.add(concurrentAuthenticationStrategy);
            delegateStrategies.add(new SessionFixationProtectionStrategy());
            delegateStrategies.add(new RegisterSessionAuthenticationStrategy(getSessionRegistry()));

            CompositeSessionAuthenticationStrategy authenticationStrategy =  new CompositeSessionAuthenticationStrategy(delegateStrategies);
            return authenticationStrategy;
    }

    @Bean
    ConcurrentSessionFilter concurrentSessionFilter() {
            CustomSessionInformationExpiredStrategy redirectStrategy = new CustomSessionInformationExpiredStrategy("/pub/multiplesessions.html");
            CustomConcurrentSessionFilter concurrentSessionFilter = new CustomConcurrentSessionFilter(getSessionRegistry(), redirectStrategy);
            return concurrentSessionFilter;
    }

CustomSessionInformationExpiredStrategy.java

public class CustomSessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {

    private Logger log = Logger.getLogger(this.getClass().getName());
    private String expiredUrl = "";

    public CustomSessionInformationExpiredStrategy(String expiredUrl) {
        this.expiredUrl = expiredUrl;
    }

    @Override
    public void onExpiredSessionDetected(SessionInformationExpiredEvent sessionInformationExpiredEvent) throws IOException, ServletException {

        log.info("Redirecting to session expired page");
        HttpServletRequest request = sessionInformationExpiredEvent.getRequest();
        HttpServletResponse response = sessionInformationExpiredEvent.getResponse();
        request.getSession();// creates a new session
        response.sendRedirect(request.getContextPath() + expiredUrl);
    }

}

CustomConcurrentSessionFilter.java,这里没有自定义代码。

public class CustomConcurrentSessionFilter extends ConcurrentSessionFilter {

    public CustomConcurrentSessionFilter(SessionRegistry sessionRegistry) {
        super(sessionRegistry);
    }

    public CustomConcurrentSessionFilter(SessionRegistry sessionRegistry, SessionInformationExpiredStrategy sessionInformationExpiredStrategy) {
        super(sessionRegistry, sessionInformationExpiredStrategy);
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        super.doFilter(req, res, chain);
    }

}