Фиксиране на 401s с CORS Предварителни полети и Пролетна сигурност

1. Общ преглед

В този кратък урок ще научим как да разрешим грешката „Отговорът за предпечат има невалиден HTTP код на състоянието 401“, която може да възникне в приложения, които поддържат комуникация с различни източници и използват Spring Security.

Първо ще видим какво представляват заявките за кръстосан произход и след това ще поправим проблемен пример.

2. Заявки за кръстосан произход

Накратко заявките за кръстосан произход са HTTP заявки, при които произходът и целта на заявката са различни. Такъв е случаят, например, когато уеб приложение се обслужва от един домейн и браузърът изпраща заявка AJAX до сървър в друг домейн.

За да управлява заявки за кръстосан произход, сървърът трябва да активира определен механизъм, известен като CORS, или Cross-Origin Resource Sharing.

Първата стъпка в CORS е заявка OPTIONS, за да се определи дали целта на заявката я поддържа. Това се нарича заявка преди полет.

След това сървърът може да отговори на заявката преди полета с колекция от заглавия:

  • Access-Control-Allow-Origin : Определя кои източници могат да имат достъп до ресурса. „*“ Представлява всеки произход
  • Access-Control-Allow-Methods : Показва разрешените HTTP методи за заявки за кръстосан произход
  • Access-Control-Allow-Headers : Показва разрешените заглавки на заявки за заявки за кръстосан произход
  • Access-Control-Max-Age : Определя времето на изтичане на резултата от кешираната заявка за предпечат

Така че, ако заявката преди полет не отговаря на условията, определени от тези заглавия на отговора, действителната заявка за последващо действие ще изведе грешки, свързани с искането за кръстосан произход.

Лесно е да добавите поддръжка на CORS към нашата услуга, задвижвана от Spring, но ако е конфигурирана неправилно, тази предполетна заявка винаги ще се провали с 401.

3. Създаване на REST API с активиран CORS

За да симулираме проблема, нека първо създадем прост REST API, който поддържа заявки за кръстосан произход:

@RestController @CrossOrigin("//localhost:4200") public class ResourceController { @GetMapping("/user") public String user(Principal principal) { return principal.getName(); } }

В @CrossOrigin анотацията гарантира, че нашите програмни интерфейси са достъпни само от произхода, посочен в неговата теза.

4. Осигуряване на нашия REST API

Нека сега защитим нашия REST API с Spring Security:

@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .httpBasic(); } }

В този клас за конфигуриране наложихме упълномощаване на всички входящи заявки. В резултат на това той ще отхвърли всички заявки без валиден токен за оторизация.

5. Изпращане на заявка преди полет

Сега, когато създадохме нашия REST API, нека опитаме предполетна заявка, използвайки curl :

curl -v -H "Access-Control-Request-Method: GET" -H "Origin: //localhost:4200" -X OPTIONS //localhost:8080/user ... < HTTP/1.1 401 ... < WWW-Authenticate: Basic realm="Realm" ... < Vary: Origin < Vary: Access-Control-Request-Method < Vary: Access-Control-Request-Headers < Access-Control-Allow-Origin: //localhost:4200 < Access-Control-Allow-Methods: POST < Access-Control-Allow-Credentials: true < Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH ...

От изхода на тази команда можем да видим, че заявката е отказана с 401.

Тъй като това е команда curl , няма да видим грешката „Отговорът за предпечат има невалиден HTTP код на състоянието 401“ в изхода.

Но можем да възпроизведем тази точна грешка, като създадем приложение отпред, което консумира нашия REST API от различен домейн и го стартираме в браузър.

6. Решението

Не сме изключили изрично заявките за предпечат от оторизация в нашата конфигурация Spring Security . Не забравяйте, че Spring Security по подразбиране осигурява всички крайни точки.

В резултат на това нашият API очаква токен за упълномощаване и в заявката OPTIONS.

Spring предоставя готово решение за изключване на OPTIONS заявки от проверки за оторизация:

@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { // ... http.cors(); } }

Методът cors () ще добави предоставения от пролетта CorsFilter към контекста на приложението, който от своя страна заобикаля проверките за оторизация за заявки за OPTIONS.

Сега можем да тестваме отново нашето приложение и да видим, че работи.

7. Заключение

В тази кратка статия научихме как да поправим грешката „Отговорът за предпечат има невалиден HTTP код на състоянието 401“, която е свързана с Spring Security и заявки за кръстосан произход.

Имайте предвид, че с примера клиентът и API трябва да работят на различни домейни или портове, за да пресъздадат проблема. Например, можем да свържем името на хоста по подразбиране с клиента и IP адреса на машината към нашия REST API, когато се изпълнява на локална машина.

Както винаги, примерът, показан в този урок, може да бъде намерен в Github.