5. OAuth 2.0 erőforrás-kiszolgáló tavaszi biztonsággal

1. Áttekintés

Ebben az oktatóanyagban megtanuljuk hogyan állítsunk be egy OAuth 2.0 erőforrás-kiszolgálót a Spring Security 5 használatával.

Ezt a JWT, valamint az átlátszatlan tokenek, a Spring Security által támogatott kétféle hordozójelző használatával fogjuk megtenni.

Mielőtt folytatnánk a megvalósítást és a kódmintákat, megalapozunk néhány hátteret.

2. Egy kis háttér

2.1. Mik azok a JWT-k és az átlátszatlan tokenek?

A JWT vagy a JSON Web Token az érzékeny információk biztonságos továbbításának egyik módja a széles körben elfogadott JSON formátumban. A tartalmazott információk vonatkozhatnak a felhasználóra vagy magára a tokenre, például annak lejáratára és kibocsátójára.

Másrészt egy átlátszatlan jelző, amint a neve is sugallja, átlátszatlan az általa hordozott információk szempontjából. A token csak egy azonosító, amely az engedélyezési kiszolgálón tárolt információkra mutat - a kiszolgáló végén belüli ellenőrzésen keresztül érvényesül.

2.2. Mi az erőforrás-kiszolgáló?

Az OAuth 2.0 kontextusában a Az erőforrás-kiszolgáló olyan alkalmazás, amely az erőforrásokat OAuth-tokeneken keresztül védi. Ezeket a tokeneket egy hitelesítési szerver adja ki, általában egy kliens alkalmazás számára. Az erőforrás-kiszolgáló feladata a token ellenőrzése, mielőtt egy erőforrást kiszolgálna az ügyfélnek.

A token érvényességét több dolog határozza meg:

  • Ez a token a konfigurált jogosultságkiszolgálótól származik?
  • Lejárt?
  • Ez az erőforrás-kiszolgáló a kívánt közönség?
  • A token rendelkezik a szükséges jogosultsággal a kért erőforráshoz való hozzáféréshez?

A megjelenítéshez nézzük meg az engedélyezési kód folyamatának sorrendjét, és nézzük meg az összes szereplőt:

Amint azt a 8. lépésben láthatjuk, amikor az ügyfélalkalmazás felhívja az erőforrás-kiszolgáló API-ját egy védett erőforráshoz való hozzáféréshez, először az engedélyezési kiszolgálóhoz megy, hogy ellenőrizze a kérelemben szereplő tokent. Engedély: Viselő fejlécet, majd válaszol az ügyfélnek.

A 9. lépésre koncentrálunk ebben az oktatóanyagban.

Rendben, most ugorjunk bele a kódrészbe. Hitelesítési kiszolgálót hozunk létre a Keycloak, egy erőforrás-kiszolgáló, amely ellenőrzi a JWT-tokeneket, egy másik erőforrás-kiszolgáló, amely ellenőrzi az átlátszatlan tokenek használatát, és néhány JUnit-teszt az ügyfélalkalmazások szimulálására és a válaszok ellenőrzésére.

3. Engedélyezési kiszolgáló

Először felállítunk egy engedélyezési kiszolgálót, vagy a tokeneket kiadó dolgot.

Ehhez a Spring Boot alkalmazásba ágyazott Keycloak-ot fogjuk használni. A Keycloak egy nyílt forráskódú identitás- és hozzáférés-kezelési megoldás. Mivel ebben az oktatóanyagban az erőforrás-kiszolgálóra összpontosítunk, nem foglalkozunk mélyebben vele.

Beágyazott Keycloak szerverünk két klienst definiál - fooClient és barClient - megfelel a két erőforrás-kiszolgáló alkalmazásunknak.

4. Erőforrás-kiszolgáló - JWT-k használata

Erőforrás-kiszolgálónknak négy fő összetevője lesz:

  • Modell - a védelemre szánt erőforrás
  • API - REST vezérlő az erőforrás leleplezéséhez
  • Biztonsági konfiguráció - osztály, amely meghatározza az API által kitett védett erőforrás hozzáférés-vezérlését
  • alkalmazás.yml - konfigurációs fájl a tulajdonságok deklarálásához, beleértve az engedélyezési kiszolgálóval kapcsolatos információkat

Lássuk őket egyesével az erőforrás-kiszolgálónkon, amely JWT-tokeneket kezel, miután lestünk a függőségekről.

4.1. Maven-függőségek

Főleg szükségünk lesz a spring-boot-starter-oauth2-erőforrás-kiszolgáló, A Spring Boot indítója az erőforrás-kiszolgálók támogatásához. Ez az indító alapértelmezés szerint tartalmazza a Spring Security szolgáltatást, ezért nem kell kifejezetten hozzáadnunk:

 org.springframework.boot spring-boot-starter-web 2.2.6.RELEASE org.springframework.boot spring-boot-starter-oauth2-resource-server 2.2.6.RELEASE org.apache.commons commons-lang3 3.9 

Ezen kívül webes támogatást is felvettünk.

Bemutató céljainkhoz az erőforrásokat véletlenszerűen generáljuk ahelyett, hogy adatbázisból kapnánk őket, némi segítséggel az Apache-tól commons-lang3 könyvtár.

4.2. Modell

Az egyszerűség kedvéért felhasználjuk Foo, POJO, mint védett erőforrásunk:

nyilvános osztály Foo {private long id; privát karakterlánc neve; // kivitelező, mérőeszközök és beállítók} 

4.3. API

Itt van a többi vezérlőnk Foo manipulálható:

@RestController @RequestMapping (value = "/ foos") public class FooController {@GetMapping (value = "/ {id}") public Foo findOne (@PathVariable Long id) {return new Foo (Long.parseLong (randomNumeric (2)) ), véletlenszerű ábécé (4); } @GetMapping public List findAll () {List fooList = new ArrayList (); fooList.add (új Foo (Long.parseLong (randomNumeric (2), randomAfabetic (4))); fooList.add (új Foo (Long.parseLong (randomNumeric (2), randomAfabetic (4))); fooList.add (új Foo (Long.parseLong (randomNumeric (2), randomAfabetic (4))); return fooList; } @ResponseStatus (HttpStatus.CREATED) @PostMapping public void create (@RequestBody Foo newFoo) {logger.info ("Foo létrehozva"); }}

Mint nyilvánvaló, rendelkezésünkre áll a GET all Foos, GET a Foo id alapján, és POST a Foo.

4.4. Biztonsági konfiguráció

Ebben a konfigurációs osztályban meghatározzuk az erőforrásunk hozzáférési szintjeit:

A @Configuration nyilvános osztályú JWTSecurityConfig kiterjeszti a WebSecurityConfigurerAdapter {@Orride védett érvénytelen konfigurációját (HttpSecurity http) a Kivételt dobja: {http .authorizeRequests (authz -> authz .antMatchers (HttpMethod.GET, "/foos/**"))has .antMatchers (HttpMethod.POST, "/foos").hasAuthority("SCOPE_write") .anyRequest (). hitelesítve ()) .oauth2ResourceServer (oauth2 -> oauth2.jwt ()); }} 

Akinek van hozzáférési tokenje, rendelkezik a olvas hatókör kaphat Foos. Annak érdekében, hogy POST egy új Foo, a tokenjüknek rendelkeznie kell egy ír hatálya.

Ezenkívül hívást adtunk a jwt () használni a oauth2ResourceServer () DSL itt jelzi a szerverünk által támogatott tokenek típusát.

4.5. alkalmazás.yml

Az alkalmazás tulajdonságaiban a szokásos portszám és a kontextus-elérési út mellett meg kell határoznunk az engedélyezési kiszolgálónk kibocsátói URI elérési útját, hogy az erőforrás-kiszolgáló felfedezhesse szolgáltatójának konfigurációját:

szerver: port: 8081 servlet: context-path: / resource-server-jwt spring: biztonság: oauth2: resourceserver: jwt: kibocsátó-uri: // localhost: 8083 / auth / realms / baeldung

Az erőforrás-kiszolgáló ezeket az információkat felhasználja az ügyfélalkalmazásból érkező JWT-tokenek hitelesítésére a sorrenddiagramunk 9. lépése szerint.

Ahhoz, hogy ez az érvényesítés a kibocsátó-uri tulajdonság, az engedélyezési szervernek működnie kell. Ellenkező esetben az erőforrás-kiszolgáló nem indul el.

Ha önállóan kell elindítanunk, akkor a jwk-set-uri tulajdonság helyett az engedélyezési kiszolgáló nyilvános kulcsokat kitevő végpontjára mutat:

jwk-set-uri: // localhost: 8083 / auth / realms / baeldung / protokoll / openid-connect / certs

És csak erre van szükségünk ahhoz, hogy szerverünk érvényesítse a JWT tokeneket.

4.6. Tesztelés

Tesztelés céljából létrehozunk egy JUnit-et. Ennek a tesztnek a végrehajtásához szükségünk van az engedélyezési kiszolgálóra, valamint az erőforrás-kiszolgálóra.

Ellenőrizzük, hogy megkapjuk-e Foos től erőforrás-kiszolgáló-jwt a-val olvas hatókörű token a tesztünkben:

@Test public void givenUserWithReadScope_whenGetFooResource_thenSuccess () {String accessToken = iegūtAccessToken ("olvasni"); Válaszválasz = RestAssured.given () .header (HttpHeaders.AUTHORIZATION, "Bearer" + accessToken) .get ("// localhost: 8081 / resource-server-jwt / foos"); assertThat (response.as (List.class)). hasSizeGreaterThan (0); }

A fenti kódban a 3. sorban hozzáférési tokent kapunk a olvas hatókör az engedélyezési kiszolgálótól, amely lefedi a sorrenddiagramunk 1–7. lépéseit.

A 8. lépést a RestAssured’S kap() hívás. A 9. lépést az erőforrás-kiszolgáló hajtja végre az általunk látott konfigurációkkal, és átlátható számunkra, mint felhasználók számára.

5. Erőforrás-kiszolgáló - átlátszatlan tokenek használata

Ezután nézzük meg ugyanazokat az összetevőket az átlátszatlan tokenek kezelésével foglalkozó erőforrás-kiszolgálónk esetében.

5.1. Maven-függőségek

Az átlátszatlan tokenek támogatásához szükségünk lesz ezekre is oauth2-oidc-sdk függőség:

 com.nimbusds oauth2-oidc-sdk 8.19 futásidejű 

5.2. Modell és vezérlő

Ehhez hozzáadunk egy Rúd forrás:

public class Bar {private long id; privát karakterlánc neve; // kivitelező, mérőeszközök és beállítók} 

Nálunk is lesz egy BarController a mi végünkhöz hasonló végpontokkal FooController előtt, hogy kitálaljon Rúds.

5.3. alkalmazás.yml

Ban,-ben alkalmazás.yml itt hozzá kell adnunk egy önvizsgálat-uri megfelel a hitelesítési kiszolgálónk önellenőrzési végpontjának. Mint korábban említettük, egy átlátszatlan tokent érvényesítenek:

szerver: port: 8082 servlet: context-path: / erőforrás-kiszolgáló-átlátszatlan rugó: biztonság: oauth2: erőforrás-kiszolgáló: átlátszatlan: introspekció-uri: // localhost: 8083 / auth / realms / baeldung / protokoll / openid-connect / token / introspect introspection-client-id: barClient introspection-client-secret: barClientSecret

5.4. Biztonsági konfiguráció

A hozzáférési szintek hasonló fenntartása a Foo a Rúd erőforrás is, ez a konfigurációs osztály hívást is kezdeményez opaqueToken () használni a oauth2ResourceServer () DSL az átlátszatlan token típus használatának jelzésére:

A @Configuration public class OpaqueSecurityConfig kiterjeszti a WebSecurityConfigurerAdapter {@Value ("$ {spring.security.oauth2.resourceserver.opaque.introspection-uri}") String introspectionUri; @Value ("$ {spring.security.oauth2.resourceserver.opaque.introspection-client-id}") Karakterlánc clientId; @Value ("$ {spring.security.oauth2.resourceserver.opaque.introspection-client-secret}") Karakterlánc clientSecret; A @Orride protected void configure (HttpSecurity http) a {http .authorizeRequests (authz -> authz .antMatchers (HttpMethod.GET, "/bars/**").hasAuthority("SCOPE_read") .antMatchers (HttpMethod.POST, /bars").hasAuthority("SCOPE_write ") .anyRequest (). hitelesített ()) .oauth2ResourceServer (oauth2 -> oauth2 .opaqueToken (token -> token.introspectionUri (this.introspectionUri) .introspentClient.introspectionClient. clientSecret))); }} 

Itt adjuk meg az engedélyezési kiszolgáló által használt kliensnek megfelelő ügyfél-hitelesítő adatokat is. Ezeket korábban a következőkben definiáltuk alkalmazás.yml.

5.5. Tesztelés

Létrehozunk egy JUnit-t az átlátszatlan token-alapú erőforrás-kiszolgálónkhoz, hasonlóan ahhoz, ahogyan a JWT-hez.

Ebben az esetben ellenőrizzük, hogy a ír hatókörű hozzáférési token POST lehet Rúd nak nek erőforrás-szerver-átlátszatlan:

@Test public void givenUserWithWriteScope_whenPostNewBarResource_thenCreated () {String accessToken = iegūtAccessToken ("olvasási írás"); Bar newBar = új Bar (Long.parseLong (randomNumeric (2)), randomAfabetic (4)); Válaszválasz = RestAssured.given () .contentType (ContentType.JSON) .header (HttpHeaders.AUTHORIZATION, "Bearer" + accessToken) .body (newBar) .log () .all () .post ("// localhost: 8082 / resource-server-opaque / bars "); assertThat (response.getStatusCode ()). isEqualTo (HttpStatus.CREATED.value ()); }

Ha a CREATED állapotot visszakapjuk, az azt jelenti, hogy az erőforrás-kiszolgáló sikeresen ellenőrizte az átlátszatlan tokent, és létrehozta a Rúd nekünk.

6. Következtetés

Ebben az oktatóanyagban láthattuk, hogyan kell konfigurálni a Spring Security alapú erőforrás-kiszolgáló alkalmazást a JWT és az átlátszatlan tokenek érvényesítésére.

Ahogy láttuk, minimális beállítással Spring lehetővé tette a tokenek zökkenőmentes hitelesítését egy kibocsátóval és küldjön erőforrásokat a kérelmező félnek - esetünkben JUnit teszt.

Mint mindig, a forráskód is elérhető a GitHubon.