A Java hitelesítés szuper feltöltése JSON web tokenekkel (JWT)

Felkészül a biztonságos hitelesítés létrehozására, vagy azzal küzd a Java alkalmazásában? Nem biztos abban, hogy milyen előnyökkel jár a tokenek (és különösen a JSON webes tokenek) használata, illetve hogyan kell ezeket telepíteni? Izgatottan válaszolok ezekre a kérdésekre, és még sok minden másra, ebben az oktatóanyagban!

Mielőtt belevetnénk magukat a JSON Web Tokenekbe (JWT) és a JJWT könyvtárba (amelyet a Stormpath CTO, Les Hazlewood készített és a közreműködők közössége gondozott), térjünk ki néhány alapra.

1. Hitelesítés vs. token hitelesítés

Az a protokollkészlet, amelyet az alkalmazás a felhasználói identitás hitelesítésének megerősítésére használ. Az alkalmazások hagyományosan a munkamenet-sütik révén megőrzik identitásukat. Ez a paradigma a munkamenet-azonosítók kiszolgálóoldali tárolásán alapul, amely arra kényszeríti a fejlesztőket, hogy egyedi vagy kiszolgálóspecifikus, vagy teljesen külön munkamenet-tárolási rétegként megvalósított munkamenet-tárolókat hozzanak létre.

A token-hitelesítést a szerveroldali munkamenet-azonosítók nem és nem sikerült problémáinak megoldására fejlesztették ki. Csakúgy, mint a hagyományos hitelesítésnél, a felhasználók is ellenőrizhető hitelesítő adatokat mutatnak be, de a munkamenet-azonosító helyett most tokeneket kapnak. A kezdeti hitelesítő adatok lehetnek a szokásos felhasználónév / jelszó pár, API kulcsok vagy akár egy másik szolgáltatás tokenjei. (A Stormpath API Key Authentication Feature példája erre.)

1.1. Miért Tokenek?

Nagyon egyszerűen a tokenek használata a munkamenet-azonosítók helyett csökkentheti a kiszolgáló terhelését, egyszerűsítheti az engedélyek kezelését, és jobb eszközöket kínál az elosztott vagy felhőalapú infrastruktúra támogatásához. A JWT esetében ez elsősorban az ilyen típusú tokenek hontalan jellege révén valósul meg (erről bővebben alább).

A tokenek sokféle alkalmazást kínálnak, például: Cross Site Request Forgery (CSRF) védelmi sémák, OAuth 2.0 interakciók, munkamenet-azonosítók és (cookie-kban) hitelesítési ábrázolásként. A legtöbb esetben a szabványok nem határoznak meg egy adott formátumot a tokenek számára. Íme egy példa egy tipikus Spring Security CSRF tokenre HTML formában:

Ha megpróbálja ezt az űrlapot megfelelő CSRF-token nélkül elküldeni, hibaüzenetet kap, és ez a tokenek hasznossága. A fenti példa „buta” token. Ez azt jelenti, hogy nincs magában rejlő jelentés, amelyet magából a tokenből kellene levonni. A JWT-k itt is nagy változást hoznak.

2. Mi van a JWT-ben?

A JWT-k (ejtsd: „jots”) URL-ben biztonságos, kódolt, kriptográfia aláírással ellátott (néha titkosított) karakterláncok, amelyek különböző alkalmazásokban használhatók tokenekként. Íme egy példa arra, hogy egy JWT-t CSRF-tokeneként használnak:

Ebben az esetben láthatja, hogy a token sokkal hosszabb, mint az előző példánkban. Csakúgy, mint korábban láthattuk, ha az űrlapot token nélkül nyújtják be, hibaüzenetet kap.

Szóval, miért a JWT?

A fenti token rejtjelesen van aláírva, ezért ellenőrizhető, igazolva, hogy nem hamisították meg. A JWT-k különféle kiegészítő információkkal vannak kódolva.

Nézzük meg a JWT anatómiáját, hogy jobban megértsük, hogyan préseljük ki belőle ezt a jóságot. Lehet, hogy észrevette, hogy három különböző szakasz van elválasztva pontokkal (.):

FejléceyJhbGciOiJIUzI1NiJ9
Hasznos tehereyJqdGkiOiJlNjc4ZjIzMzQ3ZTM0MTBkYjdlNjg3Njc4MjNiMmQ3MCIsImlhdC

I6MTQ2NjYzMzMxNywibmJmIjoxNDY2NjMzMzE3LCJleHAiOjE0NjY2MzY5MTd9

Aláírásrgx_o8VQGuDa2AqCHSgVOD5G68Ld_YYM7N7THmvLIKc

Minden szakasz base64 URL-kódolású. Ez biztosítja, hogy biztonságosan használható legyen egy URL-ben (erről bővebben később). Vizsgáljuk meg közelebbről az egyes szakaszokat külön-külön.

2.1. A Fejléc

Ha az64 fejlécet dekódolja a fejléc dekódolásával, akkor a következő JSON karakterláncot kapja:

{"alg": "HS256"}

Ez azt mutatja, hogy a JWT-t az SHA-256 segítségével írták alá a HMAC-szal.

2.2. A hasznos teher

Ha dekódolja a hasznos terhet, akkor a következő JSON karakterláncot kapja (az áttekinthetőség érdekében formázva):

{"jti": "e678f23347e3410db7e68767823b2d70", "iat": 1466633317, "nbf": 1466633317, "exp": 1466636917}

A hasznos teheren belül, amint láthatja, számos kulcs található értékekkel. Ezeket a kulcsokat „követeléseknek” nevezzük, és a JWT specifikációban ezek közül hét „regisztrált” követelésként szerepel. Ők:

issKibocsátó
alattiTantárgy
audKözönség
expLejárat
nbfAzelőtt nem
iatKiadva itt
jtiJWT azonosító

A JWT felépítésekor tetszőleges egyéni igényeket tehet fel. A fenti lista egyszerűen csak a használt kulcsban és a várható típusban is fenntartott igényeket jelöli. CSRF-jünk rendelkezik JWT azonosítóval, „Kibocsátási idő”, „Nem előtte” és Lejárati idővel. A lejárati idő pontosan egy perccel haladja meg a kiadott időpontot.

2.3. Az aláírás

Végül az aláírás szakasz úgy jön létre, hogy a fejlécet és a hasznos terhet együtt veszi fel (a. Között), és átadja a megadott algoritmuson (HMAC ebben az esetben az SHA-256-ot használva) egy ismert titokkal együtt. Vegye figyelembe, hogy a titok az mindig bájt tömböt, és olyan hosszúságúnak kell lennie, amely értelmes a használt algoritmus számára. Az alábbiakban egy véletlenszerű base64 kódolt karakterláncot használok (az olvashatóság érdekében), amelyet bájt tömbgé alakítanak át.

Pszeudokódban így néz ki:

computeHMACSHA256 (fejléc + "." + hasznos terhelés, base64DecodeToByteArray ("4pE8z3PBoHjnV1AhvGk + e8h2p + ShZpOnpr8cwHmMh1w =")

Mindaddig, amíg ismeri a titkot, maga is előállíthatja az aláírást, és összehasonlíthatja az eredményt a JWT aláírás szakaszával, hogy ellenőrizze, hogy nem hamisították-e meg. Technikailag egy kriptográfia aláírással ellátott JWT-t JWS-nek hívnak. A JWT-k is titkosíthatók, majd JWE-nek hívják őket. (A gyakorlatban a JWT kifejezést használják a JWE és JWS leírására.)

Ez visszavezet minket a JWT CSRF tokenként történő használatának előnyeihez. Ellenőrizhetjük az aláírást, és a JWT-ben kódolt információkat felhasználhatjuk annak érvényességének megerősítésére. Tehát nemcsak a JWT karakterlánc-reprezentációjának kell megfelelnie a kiszolgálóoldali tároltaknak, hanem egyszerűen ellenőrizhetjük, hogy a JWT exp követelés. Ez megmenti a szervert a további állapot fenntartásától.

Nos, rengeteg földet lefedtünk itt. Merüljünk el valamilyen kódban!

3. Állítsa be a JJWT oktatóanyagot

A JJWT (//github.com/jwtk/jjwt) egy Java könyvtár, amely végpontok közötti JSON webkockák létrehozását és ellenőrzését biztosítja. Mindörökké ingyenes és nyílt forráskódú (Apache License, 2.0-s verzió) építőközpontú kezelőfelülettel tervezték, amely a komplexitás legnagyobb részét elrejtette.

A JJWT használatának elsődleges műveletei a JWT-k felépítését és elemzését jelentik. Ezután ezeket a műveleteket nézzük meg, majd a JJWT néhány kibővített szolgáltatásával foglalkozunk, végül pedig a JWT-ket CSRF-tokenekként látjuk működésben a Spring Security, Spring Boot alkalmazásban.

A következő szakaszokban bemutatott kód itt található. Megjegyzés: A projekt a kezdetektől fogva a Spring Boot programot használja, mivel könnyen interakcióba léphet az általa kitett API-val.

A projekt felépítéséhez hajtsa végre a következőket:

git clone //github.com/eugenp/tutorials.git cd oktatóanyagok / jjwt mvn tiszta telepítés

A Spring Boot egyik nagyszerű tulajdonsága, hogy mennyire egyszerű elindítani az alkalmazást. A JJWT Fun alkalmazás futtatásához egyszerűen tegye a következőket:

java -jar cél / *. korsó 

Tíz végpont van kitéve ebben a példaalkalmazásban (a httpie-t használom az alkalmazással való interakcióhoz. Itt található.)

http localhost: 8080
Elérhető parancsok (feltételezve: httpie - //github.com/jkbrzt/httpie): http // localhost: 8080 / Ez a használati üzenet http // localhost: 8080 / static-builder a JWT-t hardveresen kódolt állításokból állítja össze. POST // localhost: 8080 / dinamikus-készítő-általános állítás-1 = érték-1 ... [állítás-n = érték-n] JWT felépítése a követelésekben átadott adatokból (általános követelések térképének felhasználásával) http POST // localhost: 8080 / dinamikus-készítő-specifikus igény -1 = érték-1 ... [állítás-n = érték-n] a JWT felépítése a követelésekben átadott értékekből (speciális igénypontok módszerével) http POST // localhost: 8080 / dynamic-builder-compress igény-1 = érték-1 ... [igény-n = érték-n] build DEFLATE tömörített JWT a követelésekben átadott http // localhost: 8080 / parser? jwt = A JWT-ben átadott elemzés http // localhost: 8080 / parser-enforce? jwt = Elemzés átadva a JWT-ben az „iss” regisztrált igény és a „hasMotorcycle” egyéni igény érvényesítése http // localhost: 8080 / get-secrets Mutassa a jelenleg használt aláíró kulcsokat. http // localhost: 8080 / refresh-secrets Új aláíró kulcsokat generál és megmutatja őket. http POST // localhost: 8080 / set-secrets HS256 = base64-encoded-value HS384 = base64-encoded-value HS512 = base64-encoded-value Kifejezetten beállítja az alkalmazásban használandó titkokat.

A következő szakaszokban megvizsgáljuk ezeket a végpontokat és a kezelőkben található JJWT kódot.

4. JWT-k építése JJWT-vel

A JJWT folyékony interfésze miatt a JWT létrehozása alapvetően három lépésből áll:

  1. A token belső igényeinek meghatározása, például Kibocsátó, Tárgy, Lejárat és ID.
  2. A JWT kriptográfiai aláírása (így JWS).
  3. A JWT tömörítése URL-ben biztonságos karaktersorozatba, a JWT Compact Serialization szabályok szerint.

A végső JWT egy három részből álló base64 kódolású karaktersorozat lesz, amelyet a megadott aláírási algoritmussal írnak alá, és a megadott kulcs segítségével. Ezt követően a token készen áll arra, hogy megossza a másik féllel.

Íme egy példa a JJWT működésére:

Karakterlánc jws = Jwts.builder () .setIssuer ("Stormpath") .setSubject ("msilverman") .claim ("név", "Micah Silverman") .claim ("hatókör", "adminok") // péntek, június 24 2016 15:33:42 GMT-0400 (EDT) .setIssuedAt (Date.from (Instant.ofEpochSecond (1466796822L))) // szombat, 2016. június 24., 2116 15:33:42 GMT-0400 (EDT) .setExpiration (Date.from (Instant.ofEpochSecond (4622470422L))) .signWith (SignatureAlgorithm.HS256, TextCodec.BASE64.decode ("Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E =")).

Ez nagyon hasonlít a kódhoz, amely a StaticJWTController.fixedBuilder a kódprojekt metódusa.

Ezen a ponton érdemes beszélni a JWT-kkel és az aláírással kapcsolatos néhány anti-mintáról. Ha látott már valaha JWT-példákat, akkor valószínűleg találkozott az alábbi aláíró mintázatellenes forgatókönyvek egyikével:

  1. .signWith (SignatureAlgorithm.HS256, "titkos" .getBytes ("UTF-8"))
  2. .signWith (SignatureAlgorithm.HS256, "Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E =". getBytes ("UTF-8"))
  3. .signWith (SignatureAlgorithm.HS512, TextCodec.BASE64.decode ("Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E ="))

Bármelyik HS típusú aláírási algoritmusok bájt tömböt vesznek fel. Az emberek számára kényelmes olvasni, ha vesz egy karakterláncot, és átalakítja azt egy bájtos tömbgé.

A fenti 1. anti-minta ezt bizonyítja. Ez problematikus, mert a titkot gyengíti az, hogy ilyen rövid, és ez nem egy bájt tömb a natív formájában. Tehát az olvashatóság megőrzése érdekében a base64 kódolhatjuk a bájt tömböt.

Azonban a fenti 2. anti-minta felveszi az base64 kódolt karakterláncot, és közvetlenül átalakítja bájt tömbgé. Mit kell tennie, az az, hogy az base64 karakterláncot visszakódolja az eredeti bájt tömbbe.

A fenti 3. szám ezt bizonyítja. Szóval, miért ez is anti-minta? Finom indok ebben az esetben. Vegye figyelembe, hogy az aláírási algoritmus HS512. A bájt tömb nem az a maximális hosszúság HS512 támogatni tudja, így gyengébb titok, mint ami az adott algoritmus számára lehetséges.

A példa kód tartalmaz egy úgynevezett osztályt Titkos szolgálat amely biztosítja a megfelelő erősség titkait az adott algoritmushoz. Az alkalmazás indításakor új titokkészlet jön létre a HS algoritmusok mindegyikéhez. Vannak végpontok a titkok frissítésére, valamint a titkok kifejezett beállítására.

Ha a projekt a fent leírtak szerint fut, hajtsa végre az alábbiakat, hogy az alábbi JWT példák megegyezzenek a projekt válaszaival.

http POST localhost: 8080 / set-titkok \ HS256 = "Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E =" \ HS384 = "VW96zL + tYlrJLNCQ0j6QPTp + d1q75n / Wa8LVvpWyG8pPZOP6AA5X7XOIlI90sDwx" \ HS512 = "cd + Pr1js + w2qfT2BoCD + tPcYp9LbjpmhSMEJqUob1mcxZ7 + Wmik4AYdjX + DlDjmE4yporzQ9tm7v3z / j + QbdYg =="

Most eltalálhatja a / static-builder végpont:

http // localhost: 8080 / static-builder

Ez egy JWT-t állít elő, amely így néz ki:

eyJhbGciOiJIUzI1NiJ9. eyJpc3MiOiJTdG9ybXBhdGgiLCJzdWIiOiJtc2lsdmVybWFuIiwibmFtZSI6Ik1pY2FoIFNpbHZlcm1hbiIsInNjb3BlIjoiYWRtaW5zIiw2WJJJJJJJJJJJJJJJJJJJJ kP0i_RvTAmI8mgpIkDFhRX3XthSdP-eqqFKGcU92ZIQ

Most nyomja meg:

http //localhost:8080/parser?jwt=eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJzdWIiOiJtc2lsdmVybWFuIiwibmFtZSI6Ik1pY2FoIFNpbHZlcm1hbiIsInNjb3BlIjoiYWRtaW5zIiwiaWF0IjoxNDY2Nzk2ODIyLCJleHAiOjQ2MjI0NzA0MjJ9.kP0i_RvTAmI8mgpIkDFhRX3XthSdP-eqqFKGcU92ZIQ

A válasznak minden olyan állítása megvan, amelyeket a JWT létrehozásakor felvetettünk.

HTTP / 1.1 200 OK Tartalom-típus: application / json; charset = UTF-8 ... {"jws": {"body": {"exp": 4622470422, "iat": 1466796822, "iss": "Stormpath "," név ":" Micah Silverman "," hatókör ":" adminok "," sub ":" msilverman "}," fejléc ": {" alg ":" HS256 "}," aláírás ":" kP0i_RvTAmI8mgpIkDFhRX3XthSdP-eqqFKGcU92ZIQ "}," status ":" SIKER "}

Ez az elemzési művelet, amelyre a következő szakaszban térünk ki.

Most nézzünk meg egy olyan végpontot, amely a követeléseket paraméterként veszi fel, és egy egyedi JWT-t épít majd nekünk.

http -v POST localhost: 8080 / dynamic-builder-general iss = Stormpath sub = msilverman hasMotorcycle: = true

jegyzet: Van egy finom különbség a hasMotorcycle követelés és a többi követelés. A httpie feltételezi, hogy a JSON paraméterek alapértelmezés szerint karakterláncok. A nyers JSON elküldéséhez a httpie használatával a := forma inkább =. Enélkül benyújtaná „HasMotorcycle”: „true”, amit nem akarunk.

Itt van a kimenet:

POST / dynamic-builder-general HTTP / 1.1 Elfogadás: application / json ... {"hasMotorcycle": true, "iss": "Stormpath", "sub": "msilverman"} HTTP / 1.1 200 OK Tartalom-típus: application / json; charset = UTF-8 ... { "JWT": "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJzdWIiOiJtc2lsdmVybWFuIiwiaGFzTW90b3JjeWNsZSI6dHJ1ZX0.OnyDs-zoL3-rw1GaSl_KzZzHK9GoiNocu-YwZ_nQNZU", "állapot": "siker"} 

Vessünk egy pillantást a végpontot támogató kódra:

@RequestMapping (value = "/ dynamic-builder-general", method = POST) public JwtResponse dynamicBuilderGeneric (@RequestBody Map követelések) dobja az UnsupportedEncodingException {String jws = Jwts.builder () .setClaims (állítások) .signgithor secretService.getHS256SecretBytes ()). kompakt (); return new JwtResponse (jws); }

A 2. vonal biztosítja, hogy a bejövő JSON automatikusan Java térképpé alakuljon át, ami nagyon hasznos a JJWT számára, mivel az 5. vonalon alkalmazott módszer egyszerűen felveszi ezt a térképet, és egyszerre állítja be az összes követelést.

Bármennyire is szűkös ez a kód, szükségünk van valami konkrétabbra, hogy az átadott követelések érvényesek legyenek. Használni a .setClaims (Térkép-követelések) A módszer akkor hasznos, ha már tudja, hogy a térképen megjelenített állítások érvényesek. Itt kerül be a JJWT könyvtárba a Java típusbiztonsága.

A JWT specifikációban meghatározott egyes regisztrált igények mindegyikéhez tartozik egy megfelelő Java módszer a JJWT-ben, amely a specifikációnak megfelelő típust veszi fel.

Nézzünk meg egy másik végpontot a példánkban, és nézzük meg, mi történik:

http -v POST localhost: 8080 / dynamic-builder-specific iss = Stormpath sub: = 5 hasMotorcycle: = true

Ne feledje, hogy egy egész számot (5) adtunk meg az „al” követeléshez. Itt van a kimenet:

POST / dynamic-builder-specifikus HTTP / 1.1 Elfogadás: application / json ... {"hasMotorcycle": true, "iss": "Stormpath", "sub": 5} HTTP / 1.1 400 Hibás kapcsolatkérés: zárja be a Content- Típus: application / json; charset = UTF-8 ... {"kivételType": "java.lang.ClassCastException", "message": "java.lang.Integer nem adható át java.lang.String", "status" ":" HIBA "}

Most hibaüzenetet kapunk, mert a kód kikényszeríti a regisztrált követelések típusát. Ebben az esetben, alatti karakterláncnak kell lennie. Itt van a kód, amely alátámasztja ezt a végpontot:

@RequestMapping (value = "/ dynamic-builder-specific", method = POST) public JwtResponse dynamicBuilderSpecific (@RequestBody Map követelések) UnsupportedEncodingException {JwtBuilder builder = Jwts.builder (); állítások.forEach ((kulcs, érték) -> {kapcsoló (kulcs) {eset "iss": builder.setIssuer ((String) érték); break; case "sub": builder.setSubject ((String) érték); break ; case "aud": builder.setAudience ((String) érték); break; case "exp": builder.setExpiration (Date.from (Instant.ofEpochSecond (Long.parseLong (value.toString ())))); break ; case "nbf": builder.setNotBefore (Date.from (Instant.ofEpochSecond (Long.parseLong (value.toString ())))); break; case "iat": builder.setIssuedAt (Date.from (Instant.ofEpochSecond) (Long.parseLong (value.toString ()))))); break; case "jti": builder.setId ((String) érték); break; alapértelmezett: builder.claim (kulcs, érték);}}); builder.signWith (SignatureAlgorithm.HS256, secretService.getHS256SecretBytes ()); return new JwtResponse (builder.compact ()); }

Csakúgy, mint korábban, a módszer elfogadja a Térkép követelések paramétereként. Ezúttal azonban az egyes regisztrált állítások specifikus módszerét hívjuk meg, amely érvényesíti a típust.

Ennek egyik finomítása a hibaüzenet pontosítása. Jelenleg csak azt tudjuk, hogy egyik állításunk nem a megfelelő típus. Nem tudjuk, melyik követelés volt hibás, vagy mi legyen annak. Itt van egy módszer, amely konkrétabb hibaüzenetet fog kapni. A jelenlegi kód hibájával is foglalkozik.

private void užtikrintiType (String registerClaim, Object value, Class várhatóType) {boolean isCorrectType = várhatóType.isInstance (érték) || VárhatóTípus == Hosszú.osztály és & egész Integer példánya; if (! isCorrectType) {String msg = "Várható típus:" + várhatóType.getCanonicalName () + "a regisztrált követeléshez: '" + registerClaim + "', de értéket kapott:" + value + "típusú:" + value. getClass (). getCanonicalName (); dobja új JwtException (msg); }}

A 3. sor ellenőrzi, hogy az átadott érték a várt típusú-e. Ha nem, akkor a JwtException dobódik a konkrét hibával. Vessünk egy pillantást erre a műveletre ugyanazzal a hívással, amelyet korábban tettünk:

http -v POST localhost: 8080 / dynamic-builder-specific iss = Stormpath sub: = 5 hasMotorcycle: = true
POST / dinamikus készítő-specifikus HTTP / 1.1 Elfogadás: alkalmazás / JSON ...User-Agent: HTTPie / 0.9.3 {"hasMotorcycle": true, "iss": "Stormpath", "sub": 5} HTTP / 1.1 400 Hibás kapcsolatkapcsolat: bezárás Content-Type: application / json; charset = UTF -8 ... {"kivételTípus": "io.jsonwebtoken.JwtException", "message": "Várható típus: java.lang.Rekorder a regisztrált követeléshez: 'sub', de értéke: 5 típusú: java.lang .Integer "," status ":" HIBA "}

Most egy nagyon konkrét hibaüzenetünk van arról, hogy a alatti a követelés a hibás.

Térjünk vissza arra a hibára a kódunkban. A kérdésnek semmi köze a JJWT könyvtárhoz. A kérdés az, hogy a Spring Bootba épített JSON-Java Object leképező túl okos a saját javunkra.

Ha van olyan módszer, amely elfogadja a Java objektumot, a JSON leképező automatikusan átalakítja a 2 147 483 647 vagy annál kisebb átadott számot Java-ba Egész szám. Hasonlóképpen automatikusan átalakítja a 2 147 483 647-nél nagyobb számot egy Java-ba Hosszú. A iat, nbf, és exp A JWT állításai szerint azt szeretnénk elérni, hogy a užtikrintiType tesztünk sikeres legyen, függetlenül attól, hogy a leképezett objektum egész vagy hosszú. Ezért van egy további záradékunk annak meghatározására, hogy az átadott érték megfelelő-e:

 logikai isCorrectType = várhatóType.isInstance (érték) || VárhatóTípus == Hosszú.osztály és & egész Integer példánya;

Ha hosszúra számítunk, de az érték az Integer példánya, akkor is azt mondjuk, hogy ez a helyes típus. Annak megértésével, hogy mi történik ezzel az érvényesítéssel, most integrálhatjuk a sajátunkba dynamicBuilderSpecific módszer:

@RequestMapping (value = "/ dynamic-builder-specific", method = POST) public JwtResponse dynamicBuilderSpecific (@RequestBody Map követelések) UnsupportedEncodingException {JwtBuilder builder = Jwts.builder (); állítások.forEach ((kulcs, érték) -> {kapcsoló (kulcs) {eset "iss": užtikrintiType (kulcs, érték, String.osztály); builder.setIssuer ((Karakterlánc) érték); törés; eset "al": užtikrintiType (kulcs, érték, String.osztály); builder.setSubject ((String) érték); break; case "aud": užtikrintiType (kulcs, érték, String.class); builder.setAudience ((String) érték); break ; case "exp": užtikrintiType (kulcs, érték, Long.class); builder.setExpiration (Date.from (Instant.ofEpochSecond (Long.parseLong (value.toString ()))))); break; case "nbf": užtikrintiType (kulcs, érték, Long.class); builder.setNotBefore (Date.from (Instant.ofEpochSecond (Long.parseLong (value.toString ()))))); break; case "iat": užtikrintiType (kulcs, érték, Long.class); builder.setIssuedAt (Date.from (Instant.ofEpochSecond (Long.parseLong (value.toString ())))); break; case "jti": užtikrintiType (kulcs, érték, String.osztály); építő .setId ((String) érték); break; alapértelmezett: builder.claim (kulcs, érték);}}); builder.signWith (SignatureAlgorithm.HS256, secretService.getHS256SecretBytes ()); return new JwtResponse (builder.compact ()); }

jegyzet: A szakasz összes példakódjában a JWT-ket aláírják a HMAC-szal az SHA-256 algoritmus segítségével. Ennek célja, hogy a példák egyszerűek legyenek. A JJWT könyvtár 12 különböző aláírási algoritmust támogat, amelyeket kihasználhat a saját kódjában.

5. JWT-k elemzése JJWT-vel

Korábban láttuk, hogy a kódpéldánknak van egy végpontja a JWT elemzésére. Ennek a végpontnak a megütése:

http //localhost:8080/parser?jwt=eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJzdWIiOiJtc2lsdmVybWFuIiwibmFtZSI6Ik1pY2FoIFNpbHZlcm1hbiIsInNjb3BlIjoiYWRtaW5zIiwiaWF0IjoxNDY2Nzk2ODIyLCJleHAiOjQ2MjI0NzA0MjJ9.kP0i_RvTAmI8mgpIkDFhRX3XthSdP-eqqFKGcU92ZIQ

ezt a választ adja:

HTTP / 1.1 200 OK Tartalom-típus: application / json; charset = UTF-8 ... {"követelések": {"body": {"exp": 4622470422, "iat": 1466796822, "iss": "Stormpath "," név ":" Micah Silverman "," hatókör ":" adminok "," sub ":" msilverman "}," fejléc ": {" alg ":" HS256 "}," aláírás ":" kP0i_RvTAmI8mgpIkDFhRX3XthSdP-eqqFKGcU92ZIQ "}," status ":" SIKER "}

A elemző módszere StaticJWTController osztály így néz ki:

@RequestMapping (value = "/ parser", method = GET) public JwtResponse parser (@RequestParam String jwt) dobja az UnsupportedEncodingException {Jws jws = Jwts.parser () .setSigningKeyResolver (secretService.getSigning). return new JwtResponse (jws); }

A 4. sor azt jelzi, hogy a bejövő karakterlánc várhatóan aláírt JWT (a JWS) lesz. És ugyanazt a titkot használjuk, amelyet a JWT aláírásakor használtunk az elemzés során. Az 5. sor értelmezi a JWT követeléseit. Belsőleg ellenőrzi az aláírást, és kivételt vet, ha az aláírás érvénytelen.

Vegyük észre, hogy ebben az esetben haladunk a SigningKeyResolver nem pedig maga a kulcs. Ez a JJWT egyik legerősebb aspektusa. A JWT fejléce jelzi az aláíráshoz használt algoritmust. Mielőtt azonban megbíznánk benne, ellenőriznünk kell a JWT-t. Úgy tűnik, ez egy fogás 22. Nézzük meg a SecretService.getSigningKeyResolver módszer:

private SigningKeyResolver signingKeyResolver = new SigningKeyResolverAdapter () {@ Nyilvános bájt felülbírálása [] ResolSigningKeyBytes (JwsHeader fejléc, Claims követelések) {return TextCodec.BASE64.decode (secrets.get (header.getAlgorithm ())) }};

A JwsHeader, Megvizsgálhatom az algoritmust, és visszaadhatom a megfelelő bájt tömböt a JWT aláírásához használt titok számára. Most a JJWT ellenőrzi, hogy a JWT-t nem manipulálták-e ennek a bájt tömbnek a kulcsaként történő használatával.

Ha eltávolítom a JWT-ben átadott utolsó karaktert (amely az aláírás része), ez a válasz:

HTTP / 1.1 400 hibás kapcsolat: bezár Tartalom-típus: alkalmazás / json; charset = UTF-8 Dátum: 2016. június 27., hétfő, hétfő, 13:19:08 GMT szerver: Apache-Coyote / 1.1 Transfer-Encoding: darabos {"kivételTípus ":" io.jsonwebtoken.SignatureException "," message ":" A JWT-aláírás nem egyezik meg a helyileg kiszámított aláírással. A JWT-érvényességet nem lehet érvényesíteni és nem szabad megbízni benne. "," status ":" ERROR "}

6. JWT-k a gyakorlatban: Spring Security CSRF tokenek

Noha ennek a bejegyzésnek a középpontjában nem a Spring Security áll, itt elmélyülünk benne, hogy bemutassuk a JJWT könyvtár valós használatát.

A webhelyek közötti kérelmek hamisítása olyan biztonsági rés, amelynek során egy rosszindulatú webhely arra készteti Önt, hogy kérelmeket nyújtson be egy olyan webhelyhez, amelybe bizalmat szerzett. Ennek egyik gyakori gyógymódja a szinkronizáló token mintázatának megvalósítása. Ez a megközelítés beszúr egy tokent a webes űrlapba, és az alkalmazásszerver ellenőrzi a bejövő tokent a tárházával, hogy megerősítse a helyes-e. Ha a token hiányzik vagy érvénytelen, a szerver hibával válaszol.

A Spring Security beépítette a szinkronizáló token mintáját. Még jobb, ha a Spring Boot és a Thymeleaf sablonokat használja, a szinkronizáló token automatikusan beillesztésre kerül.

Alapértelmezés szerint a Spring Security által használt token egy „buta” token. Ez csak egy betűk és számok sorozata. Ez a megközelítés rendben van és működik. Ebben a szakaszban tovább javítjuk az alapvető funkcionalitást azáltal, hogy JWT-ket használunk tokenként. Amellett, hogy ellenőrizzük, hogy a beküldött token a várt-e, validáljuk a JWT-t annak további bizonyítására, hogy a tokent nem hamisították meg, és annak biztosítására, hogy ne járjon le.

A kezdéshez a Spring Security-t a Java konfiguráció segítségével állítjuk be. Alapértelmezés szerint az összes elérési út hitelesítést igényel, az összes POST végponthoz pedig CSRF tokenek szükségesek. Ezt kicsit lazítani fogjuk, hogy az eddig felépítettek továbbra is működjenek.

@Configuration public class A WebSecurityConfig kiterjeszti a WebSecurityConfigurerAdapter {private String [] ignoreCsrfAntMatchers = {"/ dynamic-builder-compress", "/ dynamic-builder-general", "/ dynamic-builder-specific", "/ set-secrets"}; A @Orride védett void configure (HttpSecurity http) dobja a {http .csrf () .ignoringAntMatchers (ignoreCsrfAntMatchers) .and (). Kivételt () / autorizeRequests () .antMatchers ("/ **") .permitAll (); }}

Két dolgot csinálunk itt. Először azt mondjuk, hogy a CSRF tokenek azok nem szükséges, ha a REST API végpontjainkba (15. sor) teszünk közzé üzenetet. Másodszor azt mondjuk, hogy minden útvonalhoz engedélyezni kell a hitelesítés nélküli hozzáférést (17–18. Sor).

Erősítsük meg, hogy a Spring Security az elvárásoknak megfelelően működik. Indítsa el az alkalmazást, és nyomja meg ezt az URL-t a böngészőben:

// localhost: 8080 / jwt-csrf-form

Itt van a Thymeleaf sablon ehhez a nézethez:

Ez egy nagyon alapvető űrlap, amely beküldéskor ugyanarra a végpontra fog POST-ot küldeni. Vegye figyelembe, hogy az űrlapon nincs kifejezett hivatkozás CSRF-tokenekre. Ha megtekinti a forrást, akkor valami ilyesmit fog látni:

Ez minden megerősítés, amelyet tudnia kell arról, hogy a Spring Security működik, és hogy a Thymeleaf sablonok automatikusan beszúrják a CSRF tokent.

Ahhoz, hogy az érték JWT legyen, engedélyezünk egy egyéni beállítást CsrfTokenRepository. Így változik a tavaszi biztonsági konfigurációnk:

@Configuration nyilvános osztály A WebSecurityConfig kiterjeszti a WebSecurityConfigurerAdapter {@Autowired CsrfTokenRepository jwtCsrfTokenRepository; A @Orride védett void konfiguráció (HttpSecurity http) a {http .csrf () .csrfTokenRepository (jwtCsrfTokenRepository) .ignoringAntMatchers (ignoreCsrfAntMatchers) .and (). AutorizeRequests () .MitMatchers ("; / /; }}

Ennek összekapcsolásához szükségünk van egy konfigurációra, amely egy olyan babot tesz ki, amely visszaadja az egyéni token-adattárat. Itt van a konfiguráció:

@Configuration public class CSRFConfig {@Autowired SecretService secretService; @Bean @ConditionalOnMissingBean nyilvános CsrfTokenRepository jwtCsrfTokenRepository () {return new JWTCsrfTokenRepository (secretService.getHS256SecretBytes ()); }}

És itt van az egyéni adattárunk (a fontos bitek):

a JWTCsrfTokenRepository nyilvános osztály megvalósítja a CsrfTokenRepository {private static final Logger log = LoggerFactory.getLogger (JWTCsrfTokenRepository.class); privát bájt [] titok; public JWTCsrfTokenRepository (byte [] secret) {this.secret = titkos; } @Orride public CsrfToken geneToken (HttpServletRequest kérés) {String id = UUID.randomUUID (). ToString (). Csere ("-", ""); Dátum most = új Dátum (); Date exp = new Date (System.currentTimeMillis () + (1000 * 30)); // 30 másodperc String token; próbáld meg a {token = Jwts.builder () .setId (id) .setIssuedAt (now) .setNotBefore (now) .setExpiration (exp) .signWith (SignatureAlgorithm.HS256, secret) .compact (); } catch (UnsupportedEncodingException e) {log.error ("Nem sikerült létrehozni a CSRf JWT-t: {}", e.getMessage (), e); token = id; } return new DefaultCsrfToken ("X-CSRF-TOKEN", "_csrf", token); } @Orride public void saveToken (CsrfToken token, HttpServletRequest kérés, HttpServletResponse válasz) {...} @Orride public CsrfToken loadToken (HttpServletRequest kérés) {...}}

A generálniToken A módszer létrehoz egy JWT-t, amely a létrehozása után 30 másodperccel lejár. Ha ez a vízvezeték a helyén van, újra elindíthatjuk az alkalmazást, és megnézhetjük a forrását / jwt-csrf-form.

A rejtett mező így néz ki:

Huzzah! Most a CSRF tokenünk egy JWT. Ez nem volt túl nehéz.

Ez azonban csak a fejtörő fele. Alapértelmezés szerint a Spring Security egyszerűen elmenti a CSRF tokent, és megerősíti, hogy a webes formában elküldött token megegyezik a mentettel. Kiterjeszteni kívánjuk a funkcionalitást a JWT érvényesítéséhez és annak biztosításához, hogy lejárt. Ehhez hozzáadunk egy szűrőt. Így néz ki most a tavaszi biztonsági konfigurációnk:

@ Konfiguráció nyilvános osztály A WebSecurityConfig kiterjeszti a WebSecurityConfigurerAdapter {... @ Felülbírálás védett érvénytelen konfigurációját (HttpSecurity http) a {http .addFilterAfter (új JwtCsrfValidatorFilter (), CsrfFilter.serverTraceTraceTraceTraceTraceTraceRt. .és (). autorizeRequests () .antMatchers ("/ **") .permitAll (); } ...}

A 9. sorban felvettünk egy szűrőt, és az alapértelmezés után a szűrőláncba helyezzük CsrfFilter. Tehát, mire a szűrőnket elérjük, a JWT token (mint egész) már megerősítést nyert, hogy a Spring Security által elmentett helyes érték.

Itt van a JwtCsrfValidatorFilter (privát, mivel a Spring Security konfigurációnk belső osztálya):

a JwtCsrfValidatorFilter privát osztály kiterjeszti a OncePerRequestFilter {@Orride védett void doFilterInternal (HttpServletRequest kérés, HttpServletResponse válasz, FilterChain filterChain) dob ServletException, IOExroken Csomagot kell átvenni request.getAttribute ("_ csrf"); if (// csak akkor érdekel, ha POST "POST" .equals (request.getMethod ()) && // figyelmen kívül hagyja, ha a kérelem elérési útja szerepel az Arrays.binarySearch listánkban. (ignoreCsrfAntMatchers, request.getServletPath ()) <0 && / / győződjön meg róla, hogy van egy token tokenünk! = null) {// CsrfFilter már ellenőrizte, hogy a token megfelel-e. // Itt ellenőrizzük, hogy lejárt-e. Próbálja ki a {Jwts.parser () .setSigningKey (secret.getBytes ("UTF-8")) .parseClaimsJws (token.getToken ()); } catch (JwtException e) {// nagy valószínűséggel egy ExpiredJwtException, de ez kezelni fog minden request.setAttribute-t ("kivétel", e); response.setStatus (HttpServletResponse.SC_BAD_REQUEST); RequestDispatcher diszpécser = request.getRequestDispatcher ("lejárt-jwt"); diszpécser.forward (kérés, válasz); }} filterChain.doFilter (kérés, válasz); }}

Vessen egy pillantást a 23. sorra. A JWT-t úgy elemezzük, mint korábban. Ebben az esetben, ha Kivételt dobnak, a kérelmet továbbítják a lejárt-jwt sablon. Ha a JWT érvényesíti, akkor a feldolgozás a szokásos módon folytatódik.

Ez lezárja a kört az alapértelmezett Spring Security CSRF token viselkedés felülírása során egy JWT token adattárral és validátorral.

Ha elindítja az alkalmazást, böngésszen a / jwt-csrf-formvárjon egy kicsit több mint 30 másodpercet, és kattintson a gombra, és ilyesmit fog látni:

7. JJWT kiterjesztett szolgáltatások

Zárjuk JJWT utunkat egy szóval néhány olyan tulajdonságról, amelyek túlmutatnak a specifikáción.

7.1. A követelések érvényesítése

Az elemzési folyamat részeként a JJWT lehetővé teszi, hogy meghatározza a szükséges állításokat és értékeket. Ez nagyon hasznos, ha a JWT-kben vannak bizonyos információk, amelyeknek jelen kell lenniük ahhoz, hogy érvényesnek tekinthessék őket. Elkerüli a sok elágazási logikát a követelések kézi érvényesítéséhez. Ez a módszer szolgálja a / parser-enforce mintaprojektünk végpontja.

@RequestMapping (value = "/ parser-enforce", method = GET) public JwtResponse parserEnforce (@RequestParam String jwt) UnsupportedEncodingException {Jws jws = Jwts.parser () .requireIssuer ("Stormpace" " true) .setSigningKeyResolver (secretService.getSigningKeyResolver ()) .parseClaimsJws (jwt); return new JwtResponse (jws); }

Az 5. és 6. sor megmutatja a regisztrált követelések és az egyedi igények szintaxisát. Ebben a példában a JWT érvénytelennek minősül, ha az iss állítás nincs jelen, vagy nincs megadva: Stormpath. Ez akkor is érvénytelen lesz, ha az egyedi hasMotorcycle követelés nincs jelen, vagy nem rendelkezik az értékkel: true.

Először hozzunk létre egy JWT-t, amely a boldog utat követi:

http -v POST localhost: 8080 / dynamic-builder-specific \ iss = Stormpath hasMotorcycle: = true sub = msilverman
POST / dynamic-builder-specifikus HTTP / 1.1 Elfogadás: application / json ... {"hasMotorcycle": true, "iss": "Stormpath", "sub": "msilverman"} HTTP / 1.1 200 OK Cache-Control: no-cache, no-store, max-age = 0, must újraérvényesítés Content-Type: application / json; charset = UTF-8 ... { "JWT": "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJoYXNNb3RvcmN5Y2xlIjp0cnVlLCJzdWIiOiJtc2lsdmVybWFuIn0.qrH-U6TLSVlHkZdYuqPRDtgKNr1RilFYQJtJbcgwhR0", „status ": "SIKER" }

Most ellenőrizzük azt a JWT-t:

http -v localhost: 8080 / parser-kényszeríteni? jwt = eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJoYXNNb3RvcmN5Y2xlIjp0cnVlJTJTJTJJJJJJJJJJUJJUg
GET / elemző által érvényesíteni? JWT = http -v localhost: 8080 / elemző által érvényesíteni? JWT = eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJoYXNNb3RvcmN5Y2xlIjp0cnVlLCJzdWIiOiJtc2lsdmVybWFuIn0.qrH-U6TLSVlHkZdYuqPRDtgKNr1RilFYQJtJbcgwhR0 HTTP / 1.1 Accept: * / * ... HTTP / 1.1 200 OK Cache-Control: no- gyorsítótár, no-store, max-age = 0, újra kell érvényesíteni a Content-Type: application / json; charset = UTF-8 ... {"jws": {"body": {"hasMotorcycle": true, "iss ":" Stormpath "," sub ":" msilverman "}," header ": {" alg ":" HS256 "}," aláírás ":" qrH-U6TLSVlHkZdYuqPRDtgKNr1RilFYQJtJbcgwhR0 "}," status ":" SIKER "}

Eddig jó. Most, ezúttal hagyjuk el a hasMotorcycle-t:

http -v POST localhost: 8080 / dynamic-builder-specific iss = Stormpath sub = msilverman

Ezúttal, ha megpróbáljuk érvényesíteni a JWT-t:

http -v localhost: 8080 / parser-enforce? jwt = eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJzdWIiOiJtc2lsdmVybWFuIn0.YMONlFM1tNgttUYcxyGyGyUgcu

kapunk:

GET / elemző által érvényesíteni? JWT = http -v localhost: 8080 / elemző által érvényesíteni? JWT = eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJzdWIiOiJtc2lsdmVybWFuIn0.YMONlFM1tNgttUYukDRsi9gKIocxdGAOLaJBymaQAWc HTTP / 1.1 Accept: * / * ... HTTP / 1.1 400 Bad Request Cache-Control: no-cache , no-store, max-age = 0, újra kell érvényesíteni Kapcsolat: bezárás Content-Type: application / json; charset = UTF-8 ... {"kivételTípus": "io.jsonwebtoken.MissingClaimException", "üzenet": "A várható hasMotorcycle állítás igaz: igaz, de nem volt jelen a JWT állításokban.", "Status": "ERROR"}

Ez azt jelzi, hogy a hasMotorcycle igényünket elvárták, de hiányzott.

Tegyünk még egy példát:

http -v POST localhost: 8080 / dynamic-builder-specific iss = Stormpath hasMotorcycle: = false sub = msilverman

Ezúttal a szükséges követelés jelen van, de annak értéke rossz. Lássuk a kimenetet:

http -v localhost: 8080 / parser-enforce?
GET / elemző által érvényesíteni? JWT = http -v localhost: 8080 / elemző által érvényesíteni? JWT = eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJoYXNNb3RvcmN5Y2xlIjpmYWxzZSwic3ViIjoibXNpbHZlcm1hbiJ9.8LBq2f0eINB34AzhVEgsln_KDo-IyeM8kc-dTzSCr0c HTTP / 1.1 Accept: * / * ...HTTP / 1.1 400 hibás kérelem gyorsítótár-vezérlés: nincs-gyorsítótár, nincs-tároló, max-age = 0, újra kell érvényesíteni a kapcsolatot: bezárás Content-Type: application / json; charset = UTF-8 ... : "io.jsonwebtoken.IncorrectClaimException", "message": "A hasMotorcycle várható állítása: true, but was: false.", "status": "ERROR"}

Ez azt jelzi, hogy a hasMotorcycle követelésünk jelen volt, de ennek értéke nem volt várható.

MissingClaimException és IncorrectClaimException a barátaitok, amikor a JWT-kben érvényesítik a követeléseket, és egy olyan szolgáltatás, amellyel csak a JJWT könyvtár rendelkezik.

7.2. JWT tömörítés

Ha nagyon sok igénye van egy JWT-re, akkor az nagyra - olyan nagyra terjedhet, hogy előfordulhat, hogy egyes böngészőkben nem fér el a GET URL-ben.

Készítsünk egy nagy JWT-t:

http -v POST localhost: 8080 / dynamic-builder-specific \ iss = Stormpath hasMotorcycle: = true sub = msilverman the = gyors barna = róka ugrott = lusta = kutya \ valahol = szivárvány felett = felfelé = magas és = az álmok = álmodtál =

Itt van a JWT, amely gyárt:

eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJoYXNNb3RvcmN5Y2xlIjp0cnVlLCJzdWIiOiJtc2lsdmVybWFuIiwidGhlIjoicXVpY2siLCJicm93biI6ImZveCIsImp1bXBlZCI6Im92ZXIiLCJsYXp5IjoiZG9nIiwic29tZXdoZXJlIjoib3ZlciIsInJhaW5ib3ciOiJ3YXkiLCJ1cCI6ImhpZ2giLCJhbmQiOiJ0aGUiLCJkcmVhbXMiOiJ5b3UiLCJkcmVhbWVkIjoib2YifQ.AHNJxSTiDw_bWNXcuh-LtPLvSjJqwDvOOUcmkk7CyZA

Az a balek nagy! Nézzük meg egy kicsit más végpontot ugyanazokkal az állításokkal:

http -v POST localhost: 8080 / dynamic-builder-compress \ iss = Stormpath hasMotorcycle: = true sub = msilverman the = gyors barna = róka ugrott = lusta = kutya \ valahol = szivárvány felett = felfelé = magas és = az álmok = álmodtál =

Ezúttal:

eyJhbGciOiJIUzI1NiIsImNhbGciOiJERUYifQ.eNpEzkESwjAIBdC7sO4JegdXnoC2tIk2oZLEGB3v7s84jjse_AFe5FOikc5ZLRycHQ3kOJ0Untu8C43ZigyUyoRYSH6_iwWOyGWHKd2Kn6_QZFojvOoDupRwyAIq4vDOzwYtugFJg1QnJv-5sY-TVjQqN7gcKJ3f-j8c-6J-baDFhEN_uGn58XtnpfcHAAD__w.3_wc-2skFBbInk0YAQ96yGWwr8r1xVdbHn-uGPTFuFE

62 karakterrel rövidebb! A JWT előállításához használt módszer kódja:

A @RequestMapping (value = "/ dynamic-builder-compress", módszer = POST) public JwtResponse dynamicBuildercompress (@RequestBody Map követelések) dobja az UnsupportedEncodingException {String jws = Jwts.builder () .setClaims (állítások) .compressWecs (tömörítés) .signWith (SignatureAlgorithm.HS256, secretService.getHS256SecretBytes ()) .compact (); return new JwtResponse (jws); }

Megjegyzés a 6. sorban megadunk egy tömörítési algoritmust használni. Ennyi van benne.

Mi a helyzet a tömörített JWT-k elemzésével? A JJWT könyvtár automatikusan észleli a tömörítést, és ugyanazt az algoritmust használja a kicsomagolásra:

GET /parser?jwt=eyJhbGciOiJIUzI1NiIsImNhbGciOiJERUYifQ.eNpEzkESwjAIBdC7sO4JegdXnoC2tIk2oZLEGB3v7s84jjse_AFe5FOikc5ZLRycHQ3kOJ0Untu8C43ZigyUyoRYSH6_iwWOyGWHKd2Kn6_QZFojvOoDupRwyAIq4vDOzwYtugFJg1QnJv-5sY-TVjQqN7gcKJ3f-j8c-6J-baDFhEN_uGn58XtnpfcHAAD__w.3_wc-2skFBbInk0YAQ96yGWwr8r1xVdbHn-uGPTFuFE HTTP / 1.1 Accept: * / * ... HTTP / 1.1 200 OK Cache-Control: no-cache, nincs -store, max-age = 0, újra kell érvényesítenie a Content-Type: application / json; charset = UTF-8 ... {"állításokat": {"body": {"és": "the", "brown" : "róka", "megálmodta": "a", "álmok": "te", "hasMotorcycle": igaz, "iss": "Viharút", "ugrott": "át", "lusta": "kutya" , "szivárvány": "way", "valahol": "over", "sub": "msilverman", "a": "quick", "up": "high"}, "header": {"alg" : "HS256", "calg": "DEF"}, "aláírás": "3_wc-2skFBbInk0YAQ96yGWwr8r1xVdbHn-uGPTFuFE"}, "status": "SIKER"}

Figyelje meg a calg igény a fejlécben. Ezt automatikusan kódolták a JWT-be, és tippet ad az elemzőnek arról, hogy milyen algoritmust használjon a dekompresszióhoz.

MEGJEGYZÉS: A JWE specifikáció támogatja a tömörítést. A JJWT könyvtár egy következő kiadásában támogatni fogjuk a JWE-t és a tömörített JWE-ket. Továbbra is támogatjuk a tömörítést más típusú JWT-kben, annak ellenére, hogy nincs megadva.

8. Token Tools for Java Devs

Noha a cikk középpontjában nem a Spring Boot vagy a Spring Security állt, e két technológia használata megkönnyítette a cikkben tárgyalt összes funkció bemutatását. Képesnek kell lennie a szerver felgyújtására és el kell kezdenie a játékot az általunk tárgyalt különböző végpontokkal. Csak ütött:

http // localhost: 8080

A Stormpath szintén izgatottan várja, hogy számos nyílt forráskódú fejlesztői eszközt juttasson el a Java közösséghez. Ezek tartalmazzák:

8.1. JJWT (miről beszéltünk)

A JJWT egy könnyen használható eszköz a fejlesztők számára JWT-k létrehozására és ellenőrzésére Java-ban. A Stormpath által támogatott számos könyvtárhoz hasonlóan a JJWT is teljesen ingyenes és nyílt forráskódú (Apache License, 2.0-s verzió), így mindenki láthatja, mit és hogyan csinál. Ne habozzon jelenteni bármilyen problémát, javasolni fejlesztéseket, és még beküldeni néhány kódot!

8.2. jsonwebtoken.io és java.jsonwebtoken.io

A jsonwebtoken.io egy olyan fejlesztői eszköz, amelyet azért hoztunk létre, hogy megkönnyítsük a JWT-k dekódolását. Egyszerűen illesszen be egy meglévő JWT-t a megfelelő mezőbe a fejléc, a hasznos terhelés és az aláírás dekódolásához. A jsonwebtoken.io-t az nJWT, a legtisztább ingyenes és nyílt forráskódú (Apache License, 2.0-s verzió) JWT könyvtár biztosítja a Node.js fejlesztők számára. Ezen a webhelyen számos nyelven generált kódot is megtekinthet. Maga a weboldal nyílt forráskódú, és itt található.

A java.jsonwebtoken.io kifejezetten a JJWT könyvtár számára készült. Módosíthatja a fejléceket és a hasznos terhelést a jobb felső mezőben, megtekintheti a JJWT által létrehozott JWT-t a bal felső mezőben, és az alsó dobozokban megtekintheti a készítő és az értelmező Java kód mintáját. Maga a weboldal nyílt forráskódú, és itt található.

8.3. JWT ellenőr

A blokk új gyereke, a JWT Inspector egy nyílt forráskódú Chrome kiterjesztés, amely lehetővé teszi a fejlesztők számára, hogy közvetlenül a böngészőben ellenőrizzék és hibakereshessék a JWT-ket. A JWT-ellenőr a JWT-ket fogja felfedezni a webhelyén (cookie-kban, helyi / munkamenet-tárolókban és fejlécekben), és könnyen hozzáférhetővé teszi azokat a navigációs sávon és a DevTools panelen keresztül.

9. JWT Ez le!

A JWT-k némi intelligenciát adnak a hétköznapi tokenekhez. A kriptográfiai aláírás és ellenőrzés, a lejárati idők beépítése és az egyéb információk JWT-be történő kódolása képes megalapozni a valóban hontalan munkamenet-kezelést. Ez nagy hatással van az alkalmazások méretezésének képességére.

A Stormpath-nál JWT-ket használunk OAuth2 tokenekhez, CSRF tokenekhez és a mikroszolgáltatások közötti állításokhoz, többek között.

Miután elkezdte használni a JWT-ket, soha nem térhet vissza a múlt néma jelzőihez. Van kérdés? Üss fel a @afitnerd-n a twitteren.