Переименовано: CSRF с Angular и Spring («Метод запроса« DELETE »не поддерживается») - PullRequest
0 голосов
/ 28 декабря 2018

Я пытаюсь вызвать метод удаления моего контроллера:

Spring:

@RestController
@RequestMapping("/api")
@CrossOrigin
public class Controller
{
    @DeleteMapping("thing/item/{name}")
    public void deleteThing(@PathVariable String name)
    {
        System.out.println("CALL"); // Never called!!!
    }
}

Angular 7:

deleteTemplate(name: string) {
    const url = `host/api/thing/item/${name}`;
    return this.http.delete(url);
}

Я нашел кое-что о включении опций:

httpOptions = {
    headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};

deleteTemplate(name: string) {
    const url = `${host}/api/thing/item/${name}`; // host is not relevant, same path with GET works.
    return this.http.delete(url, this.httpOptions);
}

Но я не думаю, что это даже нужно, поскольку все, что я посылаю, находится в самой ссылке (без json).

Каждый раз, когда это:

WARN 15280 --- [io-8443-exec-10] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'DELETE' not supported]

Как это исправить?

УДАЛЕНО отправлено с ошибкой 405 и предшествующими ОПЦИЯМИ (с кодом 200).Он достигает сервера и делает эту ошибку.

EDIT

Выше приведен пример кода, который упрощен и все еще не работает.Я понимаю ваши комментарии, но хост может быть чем угодно и здесь не имеет значения.Его локальный хост сейчас и как уже упоминалось - он работает в смысле достижения конечной точки.

Чтобы проверить, не ошибаюсь ли я, я сделал следующее:

@Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;

this.requestMappingHandlerMapping.getHandlerMethods()
                .forEach((e, k) -> System.out.println(e + "   OF   " + k));

После запуска он напечатал все, что ожидал, включая:

{GET /api/thing/item/{name}}   OF   public myPackage.Thing myPackage.Controller.getThing(java.lang.String)
{DELETE /api/thing/item/{name}}   OF   public void myPackage.Controller.deleteThing(java.lang.String)

Есть идеи?

Ответы [ 2 ]

0 голосов
/ 29 декабря 2018

Проклятье.Оказывается, проблема была в CSRF, в основном в скрытой документации Angular и вводящих в заблуждение журналах фильтров Spring.

Мне потребовалось около 10 часов, чтобы заставить его работать, но только на производстве (где Angular находится на том же хосте / порту с Spring),Я попытаюсь заставить его работать в dev, но для этого требуется переписать весь модуль, поставляемый Angular, с привязкой к его настройкам по умолчанию.

Теперь о проблеме:

Все начинается с Spring Security.когда мы хотим использовать CSRF (и мы делаем).Очевидно, CsrfFilter буквально взрывается, если не может соответствовать ожидаемым токенам CSRF, и возвращается к /error.Все это происходит без ЛЮБОГО конкретного сообщения журнала, но просто Request method 'DELETE' not supported, которое, как мы знаем, присутствует.

Это относится не только к DELETE, но и ко всем запросам действий (non-GET/HEAD).

Это все указывает на «Как настроить CSRF с Angular?».Ну, вот и мы:

И это работает по умолчанию.Основан на механизме Cookie-заголовка для CSRF.

Но подождите, это еще не все!

Spring должен быть настроен для механизма Cookie-заголовка.К счастью, мы получили:

@Override
protected void configure(HttpSecurity http) throws Exception
{
    http.csrf().csrfTokenRepository(this.csrfRepo());
}

private CookieCsrfTokenRepository csrfRepo()
{
    CookieCsrfTokenRepository repo = new CookieCsrfTokenRepository();
    repo.setCookieHttpOnly(false);
    return repo;
}

, который встроен весной и на самом деле использует те же имена файлов cookie / заголовков, что и Angular.Но что случилось с repo.setCookieHttpOnly(false);?Ну ... еще одна плохо документированная вещь.Вам просто нужно установить значение false, иначе сторона Angular не будет работать.

Опять же - это работает только для производственных сборок, потому что Angular не поддерживает внешние ссылки.Больше на: Angular 6 не добавляет заголовок X-XSRF-TOKEN к http-запросу

Так что да ... чтобы он работал в dev localhost с 2 серверами, мне понадобится 1-й длявоссоздать механизм https://angular.io/api/common/http/HttpClientXsrfModule, чтобы также перехватывать запросы не по умолчанию.

РЕДАКТИРОВАТЬ

На основе комментария JB Nizet я подготовил настройку, которая работает как для разработчиков, так и для разработчиков.производство.Действительно, прокси - это круто.Если включены CSRF и SSL (в моем случае), вам также необходимо включить SSL в Angular CLI, иначе Angular не сможет использовать CSRF прокси-сервера с поддержкой SSL и, следовательно, не будет работать.

"serve": {
    "options": {
            "proxyConfig": "proxy.conf.json",
            "sslKey": "localhost.key",
            "sslCert": "localhost.crt",
            "ssl": true
    }
}

Обратите внимание, что Cert и Key будут автоматически сгенерированы, если они не найдены :) Для бэкэнда Spring вам не нужен один и тот же сертификат.Я использую отдельные JKS там.

Ура!

enter image description here

0 голосов
/ 28 декабря 2018

Добавьте косую черту / в начале вашего пути.

@DeleteMapping("/thing/item/{name}")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...