¿我怎样才能为我的api禁用CSRF弹簧安全?

时间:2017-03-12 16:42:33

标签: spring spring-boot spring-security spring-tool-suite

我使用spring安全创建一个项目,但我只有我的api问题(所有控制器都正常使用csrf)。但似乎csrf给我的api造成了问题,因为当我向我的api提出请求时,我得到:

{"id":41,"titulo":"vineta3","creationdate":1489421003000,"URL":"http://i2.kym-cdn.com/photos/images/facebook/000/125/918/RMUBQ.png","likes":0,"dislikes":0,"descripcion":"des3"}{"timestamp":1489421218765,"status":200,"error":"OK","exception":"java.lang.IllegalStateException","message":"Cannot create a session after the response has been committed","path":"/api/vineta/41/"}

最后一个信息:

{"timestamp":1489421218765,"status":200,"error":"OK","exception":"java.lang.IllegalStateException","message":"Cannot create a session after the response has been committed","path":"/api/vineta/41/"}
当我的项目没有弹簧安全时,

没有返回。我使用下一个代码进行安全配置。

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Autowired
public UserRepositoryAuthenticationProvider authenticationProvider;

@Override
protected void configure(HttpSecurity http) throws Exception {

    // Public pages
    http.authorizeRequests().antMatchers("/").permitAll();
    http.authorizeRequests().antMatchers("/login").permitAll();
    http.authorizeRequests().antMatchers("/loginerror").permitAll();
    http.authorizeRequests().antMatchers("/registro").permitAll();
    http.authorizeRequests().antMatchers("/signup").permitAll();
    http.authorizeRequests().antMatchers(HttpMethod.GET, "/api/**").permitAll();        


    // Private pages (all other pages)
    http.authorizeRequests().antMatchers("/home").hasAnyRole("USER");
    //http.authorizeRequests().antMatchers("/crearComentario/vineta/{id}").hasAnyRole("USER");

    // Login form
    http.formLogin().loginPage("/login");
    http.formLogin().usernameParameter("username");
    http.formLogin().passwordParameter("password");
    http.formLogin().defaultSuccessUrl("/home");
    http.formLogin().failureUrl("/loginerror");

    // Logout
    http.logout().logoutUrl("/logout");
    http.logout().logoutSuccessUrl("/");

}

@Override
protected void configure(AuthenticationManagerBuilder auth)
        throws Exception {
    // Database authentication provider
    auth.authenticationProvider(authenticationProvider);
}

}

和我的csrf的下一个:

@Configuration
public class CSRFHandlerConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CSRFHandlerInterceptor());
    }
}

class CSRFHandlerInterceptor extends HandlerInterceptorAdapter {

    @Override
    public void postHandle(final HttpServletRequest request,
            final HttpServletResponse response, final Object handler,
            final ModelAndView modelAndView) throws Exception {

        CsrfToken token = (CsrfToken) request.getAttribute("_csrf"); 
        modelAndView.addObject("token", token.getToken());      
    }
}

在控制台中,我可以看到以下日志: 在

org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.0.32.jar:8.0.32]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_25]
Caused by: java.lang.IllegalStateException: Cannot create a session after the response has been committed
    at org.apache.catalina.connector.Request.doGetSession(Request.java:2928) ~[tomcat-embed-core-8.0.32.jar:8.0.32]

我没有使用SingleTransactionsController,这可能是问题吗?

4 个答案:

答案 0 :(得分:6)

我不明白你使用CSRFHandlerInterceptor的原因,但如果你只想为API禁用CRSF,我有两个解决方案:

  1. 您可以向CSRF过滤器注入requireCsrfProtectionMatcher,例如:

     http
         .csrf()
             .requireCsrfProtectionMatcher(newAndRequestMatcher(CsrfFilter.DEFAULT_CSRF_MATCHER, new RegexRequestMatcher("^(?!/api/)", null)));
    

    默认匹配器是方法匹配器,第二个匹配器用于 /api/请求。

  2. 您只能为/api创建一个新的Spring Security配置,并在默认的Spring Security配置之前设置顺序,匹配没有CSRF的API URL:

    http.requestMatcher(new AntPathRequestMatcher("/api/**")).csrf().disable();
    

答案 1 :(得分:1)

Csrf设置在Spring Security中是全局的

这可以提供帮助:

http.csrf().requireCsrfProtectionMatcher(new RequestMatcher() {

        private Pattern allowedMethods = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");
       // regex to match your api url 
        private RegexRequestMatcher apiMatcher = new RegexRequestMatcher("/v[0-9]*/.*", null);

        @Override
        public boolean matches(HttpServletRequest request) {
            // No CSRF due to allowedMethod
            if(allowedMethods.matcher(request.getMethod()).matches())
                return false;

            // No CSRF due to api call
            if(request.getRequestURI().equals("/view/cpanel/Login.jsp");
                return false;

            // CSRF for everything else that is not an API call or an allowedMethod
            return true;
        }
    });

答案 2 :(得分:1)

如果您的API使用会话cookie之外的其他内容进行身份验证,例如基本身份验证或API令​​牌,那么只允许这些请求的简单方法是:

.csrf()
    .requireCsrfProtectionMatcher(new AndRequestMatcher(
        CsrfFilter.DEFAULT_CSRF_MATCHER,
        new RequestHeaderRequestMatcher(HttpHeaders.COOKIE)));

答案 3 :(得分:0)

为API和Web启用安全性的另一种方法是将其包含在SecurityConfig类中:

@Override
protected void configure(HttpSecurity http) throws Exception {
            http
            .authorizeRequests()
            .antMatchers(....)
            //form login etc
            .and().csrf().ignoringAntMatchers("/api/**");
  }