Почему аутентификация Spring Security вызывает ошибку CORS

У меня есть внутренний сервер, созданный на Java с Spring Boot, Security и Web, и клиент, созданный с помощью Angular.

В настоящее время я пытаюсь сделать простой запрос под localhost:8080/resource.

Контроллер для этого адреса показан ниже:

@RestController
public class IndexController {
    @CrossOrigin
    @RequestMapping("/resource")
    public Map<String, Object> home() {
        Map<String, Object> model = new HashMap<String, Object>();
        model.put("id", UUID.randomUUID().toString());
        model.put("content", "Hello World");

        return model;
    }
}

А клиент Angular (та часть, которая выполняет запрос) таков:

import { Component } from "@angular/core";
import { HttpClient } from "@angular/common/http";

@Component({
    selector: "app-root",
    templateUrl: "./app.component.html",
    styleUrls: ["./app.component.css"]
})
export class AppComponent {
    public title = "Security Client";
    public greeting = {};

    constructor(private http: HttpClient) {
        http.get("http://localhost:8080/resource").subscribe(data => this.greeting = data);
    }
}

Проблема с использованием только того, что было показано, заключается в том, что я получаю ошибку CORS.

Будь то удаление Spring Security с моего pom.xml или добавление этой конфигурации:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

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

        http.authorizeRequests().antMatchers("/resource").permitAll();
    }
}

Решает проблему.

Я хочу знать, почему я получаю ошибку CORS вместо 401 Unauthorized при доступе к адресу, который требует аутентификации пользователя.

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
1 276
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Согласно документации по весенней загрузке:

For security reasons, browsers prohibit AJAX calls to resources outside the current origin. For example, you could have your bank account in one tab and evil.com in another. Scripts from evil.com should not be able to make AJAX requests to your bank API with your credentials — for example withdrawing money from your account!

Cross-Origin Resource Sharing (CORS) is a W3C specification implemented by most browsers that lets you specify what kind of cross-domain requests are authorized, rather than using less secure and less powerful workarounds based on IFRAME or JSONP.

Вы получаете эту ошибку, потому что вам нужно добавить фильтр в конфигурацию безопасности. В конфигурации добавьте:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.cors()
    .and()
    .authorizeRequests().antMatchers("/resource").permitAll();
}

В этот же файл следует добавить:

@Bean
public CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Arrays.asList("*"));
    configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", 
    "DELETE", "OPTIONS"));
    configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", 
    "x-auth-token"));
    configuration.setExposedHeaders(Arrays.asList("x-auth-token"));
    UrlBasedCorsConfigurationSource source = new 
    UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);

    return source;
}

Это отлично работает для меня.

Но почему без него я получаю ошибку CORS вместо 401?

JeanCHilger 31.01.2019 00:34

Я предполагаю, что это происходит из-за того, что фильтр cors обрабатывается перед фильтром аутентификации.

André Pacheco 31.01.2019 00:43

Проверка CORS происходит перед выполнением запросов POST, GET... через запрос OPTIONS (который, кстати, называется предварительным запросом). Чтобы лучше понять поток запросов, вы можете проверить это и это.

nullptr 31.01.2019 00:54

What I wanna know is why I am getting an CORS error instead of a 401 Unauthorized when accessing an address that demands user authentication.

Вы получаете эту ошибку, потому что перед вашим фактическим запросом (POST, GET...) браузер выполняет предварительный запрос (ОПЦИИ), чтобы проверить, действительно ли вызываемый сервер может обрабатывать запросы CORS.

Во время этого запроса Access-Control-Request-Method и Access-Control-Request-Header проверяются, и в заголовок добавляется некоторая другая информация.

Вы получаете ошибку CORS, потому что ваш фактический запрос даже не выполнен, если проверка CORS не удалось по запросу OPTIONS.

Вы можете проверить блок-схему того, как работает проверка CORS здесь

Интересным моментом является то, что вы получите статус ошибки HTTP, такой как 401, только во время предполетного запроса, когда сервер не авторизован для ответа на запрос OPTIONS.

Другие вопросы по теме