Zdrojový server OAuth 2.0 s jarnou bezpečnosťou 5

1. Prehľad

V tejto príručke sa naučíme ako nastaviť server zdrojov OAuth 2.0 pomocou Spring Security 5.

Urobíme to pomocou JWT aj nepriehľadných tokenov, dvoch druhov nosných tokenov podporovaných Spring Security.

Pred prechodom na implementáciu a ukážky kódu si vytvoríme základné pozadie.

2. Malé pozadie

2.1. Čo sú JWT a nepriehľadné tokeny?

JWT alebo JSON Web Token je spôsob bezpečného prenosu citlivých informácií v široko akceptovanom formáte JSON. Obsiahnuté informácie môžu byť o používateľovi alebo o samotnom tokene, napríklad o jeho uplynutí a vydavateľovi.

Na druhej strane, nepriehľadný token, ako už názov napovedá, je nepriehľadný z hľadiska informácií, ktoré nesie. Token je iba identifikátor, ktorý odkazuje na informácie uložené na autorizačnom serveri - na konci servera sa overí introspekciou.

2.2. Čo je zdrojový server?

V kontexte OAuth 2.0, a zdrojový server je aplikácia, ktorá chráni zdroje prostredníctvom tokenov OAuth. Tieto tokeny vydáva autorizačný server, zvyčajne pre klientsku aplikáciu. Úlohou servera prostriedkov je overiť token pred poskytnutím prostriedku klientovi.

Platnosť tokenu určuje niekoľko vecí:

  • Prišiel tento token z nakonfigurovaného autorizačného servera?
  • Je to nevypršané?
  • Je tento zdrojový server zamýšľaným publikom?
  • Má token požadované oprávnenie na prístup k požadovanému prostriedku?

Na vizualizáciu sa pozrime na sekvenčný diagram toku autorizačného kódu a uvidíme všetkých aktérov v akcii:

Ako vidíme v kroku 8, keď klientská aplikácia zavolá API servera zdrojov na prístup k chránenému prostriedku, najskôr prejde na autorizačný server, aby overil token obsiahnutý v žiadosti Povolenie: Nositeľ hlavičku a potom odpovie klientovi.

V tomto tutoriáli sa zameriavame na krok 9.

Dobre, teraz skočme na časť kódu. Nastavíme autorizačný server pomocou Keycloak, server zdrojov overujúci tokeny JWT, ďalší server zdrojov overujúci nepriehľadné tokeny a niekoľko testov JUnit na simuláciu klientských aplikácií a overenie odpovedí.

3. Autorizačný server

Najskôr nastavíme autorizačný server alebo vec, ktorá vydáva tokeny.

Na tento účel použijeme Keycloak vložený do aplikácie Spring Boot. Keycloak je riešenie správy identity a prístupu typu open-source. Pretože sa v tomto výučbe zameriavame na zdrojový server, nebudeme sa mu venovať hlbšie.

Náš zabudovaný server Keycloak má definovaných dvoch klientov - fooClient a barClient - zodpovedajúci našim dvom serverovým aplikáciám zdrojov.

4. Zdrojový server - pomocou JWT

Náš zdrojový server bude mať štyri hlavné komponenty:

  • Model - zdroj na ochranu
  • API - radič REST na odhalenie zdroja
  • Konfigurácia zabezpečenia - trieda na definovanie riadenia prístupu k chránenému prostriedku, ktorý API vystavuje
  • aplikácia.yml - konfiguračný súbor na deklarovanie vlastností vrátane informácií o autorizačnom serveri

Poďme sa spolu pozrieť na náš zdrojový server, ktorý spracováva tokeny JWT, po nahliadnutí do závislostí.

4.1. Maven závislosti

Hlavne budeme potrebovať spring-boot-starter-oauth2-resource-server, Štartér Spring Boot pre podporu servera zdrojov. Tento štartér štandardne obsahuje Spring Security, takže ho nemusíme explicitne pridávať:

 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 

Okrem toho sme pridali aj webovú podporu.

Pre naše demonštračné účely budeme zdroje generovať náhodne namiesto toho, aby sme ich získavali z databázy, s určitou pomocou od Apache commons-lang3 knižnica.

4.2. Model

Aby to nebolo jednoduché, použijeme to Foo, POJO, ako náš chránený zdroj:

public class Foo {private long id; súkromné ​​meno reťazca; // konštruktor, getri a nastavovatelia} 

4.3. API

Tu je náš radič odpočinku Foo k dispozícii na manipuláciu:

@RestController @RequestMapping (value = "/ foos") verejná trieda FooController {@GetMapping (value = "/ {id}") verejné Foo findOne (@PathVariable Long id) {návrat nového Foo (Long.parseLong (randomNumeric (2)) ), randomAlphabetic (4)); } @GetMapping public List findAll () {List fooList = new ArrayList (); fooList.add (new Foo (Long.parseLong (randomNumeric (2)), randomAlphabetic (4))); fooList.add (new Foo (Long.parseLong (randomNumeric (2)), randomAlphabetic (4))); fooList.add (new Foo (Long.parseLong (randomNumeric (2)), randomAlphabetic (4))); návrat fooList; } @ResponseStatus (HttpStatus.CREATED) @PostMapping public void create (@RequestBody Foo newFoo) {logger.info ("Foo created"); }}

Ako je zrejmé, máme ustanovenie ZÍSKAŤ všetky Foos, ZÍSKAJTE a Foo podľa id a POST a Foo.

4.4. Konfigurácia zabezpečenia

V tejto konfiguračnej triede definujeme úrovne prístupu pre náš zdroj:

@Configuration verejná trieda JWTSecurityConfig rozširuje WebSecurityConfigurerAdapter {@Override protected void configure (HttpSecurity http) vyvolá výnimku {http .authorizeRequests (authz -> authz .antMatchers (HttpMethod.GET, "/foos/**" ).hasAuthor) .antMatchers (HttpMethod.POST, "/foos").hasAuthority("SCOPE_write") .anyRequest (). authenticated ()) .oauth2ResourceServer (oauth2 -> oauth2.jwt ()); }} 

Každý, kto má prístupový token a má čítať rozsah môže dostať Foos. Za účelom zverejnenia nového Foo, ich token by mal mať a napíš rozsah.

Navyše, pridali sme hovor na jwt () pomocou oauth2ResourceServer () DSL na označenie typu tokenov podporovaných našim serverom tu.

4.5. aplikácia.yml

Vo vlastnostiach aplikácie je okrem obvyklého čísla portu a kontextu cesty aj musíme definovať cestu k URI vydavateľa nášho autorizačného servera, aby server zdrojov mohol zistiť konfiguráciu svojho poskytovateľa:

server: port: 8081 servlet: kontextová cesta: / resource-server-jwt pružina: zabezpečenie: oauth2: resourceserver: jwt: issuer-uri: // localhost: 8083 / auth / realms / baeldung

Zdrojový server používa tieto informácie na overenie tokenov JWT prichádzajúcich z klientskej aplikácie podľa kroku 9 nášho sekvenčného diagramu.

Aby táto validácia fungovala pomocou vydavateľ-uri musí byť autorizačný server funkčný. V opačnom prípade by sa zdrojový server nespustil.

Ak to potrebujeme spustiť nezávisle, môžeme dodať jwk-set-uri namiesto toho ukážte na koncový bod autorizačného servera vystavujúci verejné kľúče:

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

A to je všetko, čo potrebujeme, aby náš server mohol overovať tokeny JWT.

4.6. Testovanie

Na testovanie nastavíme JUnit. Na vykonanie tohto testu potrebujeme funkčný autorizačný server aj server zdrojov.

Overme si, či môžeme získať Foos z zdroj-server-jwt s a čítať rozsahovaný token v našom teste:

@Test public void givenUserWithReadScope_whenGetFooResource_thenSuccess () {String accessToken = obtainAccessToken ("read"); Response response = RestAssured.given () .header (HttpHeaders.AUTHORIZATION, "Bearer" + accessToken) .get ("// localhost: 8081 / resource-server-jwt / foos"); assertThat (response.as (List.class)). hasSizeGreaterThan (0); }

Vo vyššie uvedenom kóde na riadku č. 3 získame prístupový token s čítať rozsah z autorizačného servera pokrývajúci kroky od 1 do 7 nášho sekvenčného diagramu.

Krok 8 vykonáva Upokojený‘S dostať () hovor. Krok 9 vykonáva zdrojový server s konfiguráciami, ktoré sme videli, a je pre nás ako používateľov transparentný.

5. Zdrojový server - použitie nepriehľadných tokenov

Ďalej sa pozrime na rovnaké komponenty pre náš server zdrojov, ktorý spracováva nepriehľadné tokeny.

5.1. Maven závislosti

Na podporu nepriehľadných tokenov budeme navyše potrebovať oauth2-oidc-sdk závislosť:

 com.nimbusds oauth2-oidc-sdk 8.19 runtime 

5.2. Model a ovládač

Pre tento pridáme a Bar zdroj:

public class Bar {private long id; súkromné ​​meno reťazca; // konštruktor, getri a nastavovatelia} 

Budeme mať aj BarController s koncovými bodmi podobnými nášmu FooController predtým, aby sa jedlo Bars.

5.3. aplikácia.yml

V aplikácia.yml tu budeme musieť pridať introspekcia-uri zodpovedajúce introspekčnému koncovému bodu nášho autorizačného servera. Ako už bolo spomenuté, takto sa overuje nepriehľadný token:

server: port: 8082 servlet: kontextová cesta: / zdroj-server-nepriehľadná pružina: zabezpečenie: oauth2: zdrojový server: nepriehľadný: introspection-uri: // localhost: 8083 / auth / realms / baeldung / protocol / openid-connect / token / introspect introspection-client-id: barClient introspection-client-secret: barClientSecret

5.4. Konfigurácia zabezpečenia

Ponecháva podobné úrovne prístupu ako v Foo pre Bar tiež zdroj, táto konfiguračná trieda tiež zavolá opaqueToken () pomocou oauth2ResourceServer () DSL na označenie použitia nepriehľadného typu tokenu:

@Configuration verejná trieda OpaqueSecurityConfig rozširuje WebSecurityConfigurerAdapter {@Value ("$ {spring.security.oauth2.resourceserver.opaque.introspection-uri}") String introspectionUri; @Value ("$ {spring.security.oauth2.resourceserver.opaque.introspection-client-id}") String clientId; @Value ("$ {spring.security.oauth2.resourceserver.opaque.introspection-client-secret}") String clientSecret; @Override protected void configure (HttpSecurity http) vyvolá výnimku {http .authorizeRequests (authz -> authz .antMatchers (HttpMethod.GET, "/bars/**" ).hasAuthority("SCOPE_read") .antMatchers (HttpMethod.POST, " /bars").hasAuthority("SCOPE_write ") .anyRequest (). authenticated ()) .oauth2ResourceServer (oauth2 -> oauth2 .opaqueToken (token -> token.introspectionUri (this.introspectionUri) .introspectionClientCredentials this clientSecret))); }} 

Tu tiež špecifikujeme poverenia klienta zodpovedajúce klientovi autorizačného servera, ktorého budeme používať. Tieto sme definovali skôr v našom aplikácia.yml.

5.5. Testovanie

Nastavíme JUnit pre náš nepriehľadný zdrojový server založený na tokenoch, podobne ako sme to urobili pre server JWT.

V takom prípade skontrolujeme, či a napíš obmedzený prístupový token môže POST a Bar do nepriehľadný zdrojový server:

@Test public void givenUserWithWriteScope_whenPostNewBarResource_thenCreated () {String accessToken = obtainAccessToken ("read write"); Bar newBar = new Bar (Long.parseLong (randomNumeric (2)), randomAlphabetic (4)); Response response = 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 ()); }

Ak dostaneme stav CREATED späť, znamená to, že server zdrojov úspešne overil nepriehľadný token a vytvoril Bar pre nás.

6. Záver

V tomto tutoriáli sme videli, ako nakonfigurovať aplikáciu servera zdrojov založenú na Spring Security na overovanie JWT, ako aj nepriehľadných tokenov.

Ako sme videli, s minimálnym nastavením umožnila Spring bezproblémovo overiť tokeny u vydavateľa a pošlite zdroje žiadajúcej strane - v našom prípade test JUnit.

Ako vždy, zdrojový kód je k dispozícii na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found