我使用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,这可能是问题吗?
答案 0 :(得分:6)
我不明白你使用CSRFHandlerInterceptor
的原因,但如果你只想为API禁用CRSF,我有两个解决方案:
您可以向CSRF过滤器注入requireCsrfProtectionMatcher
,例如:
http
.csrf()
.requireCsrfProtectionMatcher(newAndRequestMatcher(CsrfFilter.DEFAULT_CSRF_MATCHER, new RegexRequestMatcher("^(?!/api/)", null)));
默认匹配器是方法匹配器,第二个匹配器用于不 /api/
请求。
您只能为/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/**");
}