Я создал простое приложение с Spring ботинком и Spring безопасностью, которая содержит:защита CSRF мешает мне загрузить файл
- Формы Войти
- «загрузить» форму (с соответствующим контроллером на стороне BACKEND в)
Задача: Весна безопасности имеет встроенную защиту CSRF по умолчанию. Он хорошо работает с общим REST звонками, но мне мешает загрузку файла: Я получаю сообщение об ошибке:
Недопустимого CSRF лексема «нулевой» была найдено в параметре запроса «_csrf» или заголовок «X-XSRF- ЗНАК».
Если я деактивирую защиту CSRF, я могу успешно загрузить файл.
Для иллюстрации проблемы я создал SSCCE. Шаги по воспроизведению являются:
- Запуск приложения (Основной класс
com.denodev.Application
) - Подключение к
localhost:8080
- Authenticate с этими учетными данными:
- Логин:
user
- Пароль:
password
- Логин:
- При перенаправлении в форму «загрузить» попробуйте загрузить любой файл.
- В классе
Application
не стесняйтесь активировать/деактивировать защиту CSRF, перезапустить приложение и повторить попытку.
Соответствующая часть кода:
@RestController
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
@RequestMapping(value = "/upload-file", method = RequestMethod.POST)
@ResponseBody
public String uploadFile(@RequestParam("file") MultipartFile file) {
return "Successfully received file "+file.getOriginalFilename();
}
@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/**/*.html", "login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.successHandler(successHandler())
.failureHandler(failureHandler())
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler())
.authenticationEntryPoint(authenticationEntryPoint())
.and()
//1 : Uncomment to activate csrf protection
.csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
//2 : Uncomment to disable csrf protection
//.csrf().disable()
;
}
/**
* Return HTTP 200 on authentication success instead of redirecting to a page.
*/
private AuthenticationSuccessHandler successHandler() {
return new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
}
};
}
/**
* Return HTTP 401 on authentication failure instead of redirecting to a page.
*/
private AuthenticationFailureHandler failureHandler() {
return new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
httpServletResponse.getWriter().write(e.getMessage());
}
};
}
/**
* Return HTTP 403 on "access denied" instead of redirecting to a page.
*/
private AccessDeniedHandler accessDeniedHandler() {
return new AccessDeniedHandler() {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
httpServletResponse.getWriter().write(e.getMessage());
}
};
}
private AuthenticationEntryPoint authenticationEntryPoint() {
return new AuthenticationEntryPoint() {
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
httpServletResponse.getWriter().write(e.getMessage());
}
};
}
Что я пробовал:
Spring security's documentation о MULTIPART советы разместить MultipartFilter
до весны безопасности. Он хорошо объясняет, как это сделать с простым старым webapp, отредактировав файл web.xml
. Это неприменимо к Spring Boot, и я не могу понять, что такое эквивалентный синтаксис.
Я попытался разоблачить MultipartFilter
с аннотациями @Bean
и Order
с несколькими вариантами, но я все еще борюсь с ним.
Любые идеи?
Do вы отправляете загруженный файл в HTTP-запрос AngularJs? –
@BillBilal В контексте этого SSCCE нет, но я пробовал то же самое с вызовом Angular/AJAX и получал ту же проблему. –
В моем случае это работает. Я добавил директиву для загрузки файла на стороне клиента, после чего отправлю его в запрос по электронной почте AngularJs. AngularJs добавляет токен X-XSRF-TOKEN к каждому HTTP-запросу. –