Fixing 401s med CORS Preflights og Spring Security

1. Oversigt

I denne korte vejledning lærer vi, hvordan vi løser fejlen "Svar til preflight har ugyldig HTTP-statuskode 401", som kan forekomme i applikationer, der understøtter krydskildekommunikation og bruger Spring Security.

Først ser vi, hvad krydsoprindelsesanmodninger er, og så løser vi et problematisk eksempel.

2. Anmodninger om krydsoprindelse

Krydsoprindelsesanmodninger er kort sagt HTTP-anmodninger, hvor anmodningens oprindelse og mål er forskellige. Dette er f.eks. Tilfældet, når en webapplikation serveres fra et domæne, og browseren sender en AJAX-anmodning til en server i et andet domæne.

For at administrere krydsoprindelsesanmodninger skal serveren aktivere en bestemt mekanisme kendt som CORS eller Cross-Origin Resource Sharing.

Det første trin i CORS er et MULIGHEDER anmodning om at afgøre, om målet for anmodningen understøtter det. Dette kaldes en anmodning før flyvning.

Serveren kan derefter svare på anmodningen før flyvning med en samling overskrifter:

  • Adgangskontrol-Tillad oprindelse: Definerer, hvilke oprindelser der kan have adgang til ressourcen. Et '*' repræsenterer enhver oprindelse
  • Adgangskontrol-tillad-metoder: Angiver de tilladte HTTP-metoder til anmodninger på tværs af oprindelse
  • Adgangskontrol-tillad-headere: Angiver de tilladte anmodningsoverskrifter for anmodninger på tværs af oprindelse
  • Adgangskontrol-maks. Alder: Definerer udløbstiden for resultatet af den cachelagrede preflight-anmodning

Så hvis anmodningen før flyvningen ikke opfylder betingelserne, der er fastlagt fra disse svaroverskrifter, vil den faktiske opfølgningsanmodning kaste fejl relateret til krydsoprindelsesanmodningen.

Det er let at tilføje CORS-support til vores Spring-powered service, men hvis den er konfigureret forkert, vil denne anmodning før flyvning altid mislykkes med en 401.

3. Oprettelse af en CORS-aktiveret REST API

For at simulere problemet, lad os først oprette en simpel REST API, der understøtter krydsoprindelsesanmodninger:

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

Det @CrossOrigin annotation sørger for, at vores API'er kun er tilgængelige fra den oprindelse, der er nævnt i dens argument.

4. Sikring af vores REST API

Lad os nu sikre vores REST API med Spring Security:

@EnableWebSecurity offentlig klasse WebSecurityConfig udvider WebSecurityConfigurerAdapter {@ Override-beskyttet ugyldig konfiguration (HttpSecurity http) kaster undtagelse {http .authorizeRequests () .anyRequest (). Godkendt (). Og () .httpBasic (); }}

I denne konfigurationsklasse har vi håndhævet autorisation til alle indgående anmodninger. Som et resultat afviser det alle anmodninger uden et gyldigt autorisationstoken.

5. Foretage en anmodning før flyvning

Nu hvor vi har oprettet vores REST API, lad os prøve en anmodning før flyvning ved hjælp af krølle:

curl -v -H "Access-Control-Request-Method: GET" -H "Oprindelse: // localhost: 4200" -X INDSTILLINGER // localhost: 8080 / bruger ... <HTTP / 1.1 401 ... <WWW -Authenticate: Basic realm = "Realm" ... <Varier: Oprindelse <Varier: Adgangskontrol-Anmodningsmetode <Varier: Adgangskontrol-Anmod-overskrifter <Adgangskontrol-Tillad oprindelse: // localhost: 4200 <Adgangskontrol-tillad-metoder: POST <Adgangskontrol-tillad-legitimationsoplysninger: sand <Tillad: FÅ, HEAD, POST, PUT, SLET, SPOR, INDSTILLINGER, PATCH ...

Fra output af denne kommando kan vi se det anmodningen blev afvist med en 401.

Da dette er en krølle kommando, vil vi ikke se fejlen "Svar til preflight har ugyldig HTTP-statuskode 401" i output.

Men vi kan reproducere denne nøjagtige fejl ved at oprette en frontend-applikation, der bruger vores REST API fra et andet domæne og kører den i en browser.

6. Løsningen

Vi har ikke eksplicit ekskluderet preflight-anmodningerne fra autorisation i vores Spring Security-konfiguration. Husk, at Spring Security er sikret alle slutpunkter som standard.

Som resultat, vores API forventer også et godkendelsestoken i OPTIONS-anmodningen.

Spring giver en out of the box-løsning til at udelukke OPTIONS-anmodninger fra godkendelseskontrol:

@EnableWebSecurity offentlig klasse WebSecurityConfig udvider WebSecurityConfigurerAdapter {@ Override-beskyttet ugyldig konfiguration (HttpSecurity http) kaster undtagelse {// ... http.cors (); }}

Det cors () metoden vil tilføje den foråret leverede CorsFilter til applikationskonteksten, som igen omgår godkendelseskontrol af OPTIONS-anmodninger.

Nu kan vi teste vores ansøgning igen og se, at den fungerer.

7. Konklusion

I denne korte artikel har vi lært, hvordan vi løser fejlen "Svar til preflight har ugyldig HTTP-statuskode 401", der er knyttet til Spring Security og krydsoprindelsesanmodninger.

Bemærk, at klienten og API'en med eksemplet skal køre på forskellige domæner eller porte for at genskabe problemet. For eksempel kan vi kortlægge standardværtsnavnet til klienten og maskinens IP-adresse til vores REST API, når vi kører på en lokal maskine.

Som altid kan eksemplet vist i denne vejledning findes på Github.