Я использую Spring Загрузите с помощью Spring Поддержка безопасности и коррекции.
Если я выполняю следующий код
url = 'http://localhost:5000/api/token'
xmlhttp = new XMLHttpRequest
xmlhttp.onreadystatechange = ->
if xmlhttp.readyState is 4
console.log xmlhttp.status
xmlhttp.open "GET", url, true
# xmlhttp.setRequestHeader "X-Requested-With", "XMLHttpRequest"
xmlhttp.setRequestHeader 'Authorization', 'Basic ' + btoa 'a:a'
do xmlhttp.send
Я получаю в результате
200
Если я тестирую неправильные учетные данные, например
url = 'http://localhost:5000/api/token'
xmlhttp = new XMLHttpRequest
xmlhttp.onreadystatechange = ->
if xmlhttp.readyState is 4
console.log xmlhttp.status
xmlhttp.open "GET", url, true
# xmlhttp.setRequestHeader "X-Requested-With", "XMLHttpRequest"
xmlhttp.setRequestHeader 'Authorization', 'Basic ' + btoa 'a:aa'
do xmlhttp.send
вместо получения 401 (это стандартный код для неправильной аутентификации в Spring безопасности), я получаю
0
со следующим уведомлением браузера:
GET http://localhost:5000/api/token
XMLHttpRequest не может загрузить http://localhost:5000. В запрошенном ресурсе нет заголовка "Access-Control-Allow-Origin". Origin 'http://localhost:3000', следовательно, не допускается. В ответе был код статуса HTTP 401.
Я разрабатываю код переднего плана, который нуждается в полезных кодах статуса http из ответов сервера, чтобы справиться с ситуацией. Мне нужно что-то более полезное, чем 0. Также тело ответа пуст. Я не знаю, является ли моя конфигурация неправильной, или это ошибка программного обеспечения, и я также не знаю, где, если это хром (с использованием архивного linux) или Spring безопасности.
My Spring Config:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@RestController
@RequestMapping("api")
public class Controller {
@RequestMapping("token")
@CrossOrigin
Map<String, String> token(HttpSession session) {
return Collections.singletonMap("token", session.getId());
}
}
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("a").password("a").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.anyRequest().authenticated()
.and().httpBasic();
}
}
Если я тестирую с помощью curl, все работает отлично, я думаю, потому что поддержка CORS не нужна, но я пытался имитировать запросы CORS с запросами OPTION, и результат тоже был в порядке.
$ curl -v localhost:5000/api/token -H "Authorization: Basic YTpha"
* Trying ::1...
* Connected to localhost (::1) port 5000 (#0)
> GET /api/token HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.48.0
> Accept: */*
> Authorization: Basic YTpha
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Access-Control-Allow-Origin: http://localhost:3000
< Access-Control-Allow-Methods: POST,GET,OPTIONS,DELETE
< Access-Control-Max-Age: 3600
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Headers: Origin,Accept,X-Requested- With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization
< x-auth-token: 58e4cca9-7719-46c8-9180-2fc16aec8dff
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sun, 01 May 2016 16:15:44 GMT
<
* Connection #0 to host localhost left intact
{"token":"58e4cca9-7719-46c8-9180-2fc16aec8dff"}
и с неправильными учетными данными:
$ curl -v localhost:5000/api/token -H "Authorization: Basic YTp"
* Trying ::1...
* Connected to localhost (::1) port 5000 (#0)
> GET /api/token HTTP/1.1
> Host: localhost:5000
> User-Agent: curl/7.48.0
> Accept: */*
> Authorization: Basic YTp
>
< HTTP/1.1 401 Unauthorized
< Server: Apache-Coyote/1.1
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< WWW-Authenticate: Basic realm="Realm"
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sun, 01 May 2016 16:16:15 GMT
<
* Connection #0 to host localhost left intact
{"timestamp":1462119375041,"status":401,"error":"Unauthorized","message":"Failed to decode basic authentication token","path":"/api/token"}
Изменить: Во избежание недоразумений. Я использую 1.3.3 Spring Boot. Запись в блоге пишет:
Поддержка CORS будет доступна в предстоящей версии Spring Boot 1.3 и уже доступна в сборниках 1.3.0.BUILD-SNAPSHOT.
Использование метода контроллера Конфигурация CORS с аннотациями @CrossOrigin в вашем приложении Spring для загрузки не требует какой-либо конкретной конфигурации.
Глобальную конфигурацию CORS можно определить, зарегистрировав WebMvcConfigurer bean с помощью настраиваемого метода addCorsMappings (CorsRegistry):
Я добавил следующий код для поддержки глобальной поддержки cors. на самом деле я пробовал это раньше, но результат был тот же. Я попробовал это недавно, и результат тот же.
@Configuration
public class MyConfiguration {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**");
}
};
}
}
Идея о том, что проблема связана с переадресацией между процессом авторизации, является интересной. как я могу изменить перенаправление на любые ресурсы, чтобы избежать этого конфликта?
EDIT:
Думаю, я ближе к решению. Я протестировал с моим сервером nodejs, который поддерживает без проблем, добавив Access-Control-Allow-Origin: * ко всем запросам.
Как уже упоминалось, Стефан Иселе уже упоминал, что защита Spring переадресовывает или не добавляет заголовок CORS, поэтому запрос кажется сломанным. Поэтому, пока защита Spring проверяет аутентификацию, она должна добавить правильный заголовок.
Кто-нибудь знает, как это сделать?
EDIT:
Я нашел обходное решение, которое кажется уродливым. Я начал проблему github для загрузки Spring, где описываю обходной путь: https://github.com/spring-projects/spring-boot/issues/5834