Spring Security CookieTheftException

4

我正在使用Spring Boot应用程序中的PersistentTokenBasedRememberMeServices (Spring Security 4.0.3)。以下是令牌配置片段:

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
        .failureHandler(myAuthenticationFailureHandler).loginProcessingUrl("/login").usernameParameter("username").passwordParameter("password")
        .and().exceptionHandling()
        .and().authorizeRequests()
        .antMatchers(this.getOpenURLS()).permitAll().anyRequest().authenticated().and().addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class).csrf().csrfTokenRepository(csrfTokenRepository())
        .and().rememberMe().rememberMeServices(rememberMeServices()).key(C_REMEMBER_ME_APP_KEY).and().logout();
    }

    @Bean
    public AbstractRememberMeServices rememberMeServices() {
        PersistentTokenBasedRememberMeServices rememberMeServices = null;
        try {
            rememberMeServices = new PersistentTokenBasedRememberMeServices(C_REMEMBER_ME_APP_KEY, userDetailsService, persistentTokenRepository());
            rememberMeServices.setTokenValiditySeconds((int) TimeUnit.SECONDS.convert(2, TimeUnit.DAYS));
            rememberMeServices.setParameter(C_REMEMBER_ME_PARAMETER);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return rememberMeServices;
    }

配置按预期工作,我的问题是无法处理/捕获org.springframework.security.web.authentication.rememberme.CookieTheftException异常。例如,由于我想确保能够捕获此异常,所以我启动了一个用户会话,进入数据库并更改了令牌(到存储在浏览器中的不同值),然后重新启动了Tomcat服务器。当我尝试访问应用程序时,立即抛出CookieTheftException异常。
我的配置中有一个SimpleMappingExceptionResolver Bean,如下所示:
@Bean(name = "simpleMappingExceptionResolver")
public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() {
    SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver();        
    Properties mappings = new Properties();

    mappings.setProperty("CookieTheftException", "cookieException");
    mappings.setProperty(".CookieTheftException", "cookieException");
    mappings.setProperty("org.springframework.security.web.authentication.rememberme.CookieTheftException", "cookieException");

    r.setOrder(Integer.MIN_VALUE);
    r.setExceptionMappings(mappings); 
    r.setDefaultErrorView("error"); 
    r.setExceptionAttribute("ex");
    r.setWarnLogCategory("example.MvcLogger");
    return r;
}

另外,我添加了一个@ControllerAdvice,如下所示:

@ControllerAdvice
public class GlobalDefaultExceptionHandler {

public static final String DEFAULT_ERROR_VIEW = "errorCookie";

@ExceptionHandler(value = Exception.class)
public ModelAndView defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {

    ModelAndView mav = new ModelAndView();
    mav.addObject("exception", e);
    mav.addObject("url", req.getRequestURL());
    mav.setViewName(DEFAULT_ERROR_VIEW);
    return mav;
}

很不幸,这些都无法捕获异常。奇怪的是,如果在我的任何控制器中手动引发异常,则当前配置可以成功处理异常。

看起来由于DispatcherServlet抛出异常,@ControllerAdvice和SimpleMappingExceptionResolver都无法捕获异常?我有什么遗漏吗?任何帮助将不胜感激。谢谢。


有什么帮助吗?我找到了一个解决方法,使用一个ErrorController来检查异常类型,并在CookieTheftException时进行重定向,但我相信有更好的方法来解决这个问题。请告诉我。谢谢。 - Mike
1个回答

1
我曾经苦苦挣扎,但却找不到任何有意义的解决方法。当我研究使用ErrorController作为解决方法时,我发现BasicErrorController中写道:

* {@code @ExceptionHandler})或通过添加servlet * {@link AbstractEmbeddedServletContainerFactory#setErrorPages container error pages}。

既然您说您的解决方法可行,我想通过将它们添加到servlet容器中的addErrorPages来捕获相同的错误。在我的@Configuration类中,我终于找到了答案:

@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
    return container -> {
        container.addErrorPages(new ErrorPage(CookieTheftException.class, "/login"));
    };
}

我希望在遇到这种异常后,用户需要重新登录,因此你可以看到我只是将他们发送到登录页面。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接