Overlad Java-autentisering med JSON Web Tokens (JWTs)

Gjør deg klar til å bygge, eller sliter med, sikker autentisering i Java-applikasjonen din? Usikker på fordelene med å bruke tokens (og spesielt JSON web tokens), eller hvordan de skal distribueres? Jeg er spent på å svare på disse spørsmålene og mer til deg i denne veiledningen!

Før vi dykker inn i JSON Web Tokens (JWTs), og JJWT-biblioteket (opprettet av Stormpaths CTO, Les Hazlewood og vedlikeholdt av et fellesskap av bidragsytere), la oss dekke noen grunnleggende ting.

1. Autentisering vs. tokenautentisering

Protokollsettet et program bruker for å bekrefte brukeridentitet er autentisering. Søknader har tradisjonelt vedvaret identitet gjennom øktcookies. Dette paradigmet er avhengig av server-lagring av økt-ID-er som tvinger utviklere til å opprette øktlagring som enten er unik og serverspesifikk, eller implementeres som et helt eget øktlagringslag.

Token-autentisering ble utviklet for å løse problemer ID-er for server-side økte ikke, og kunne ikke. Akkurat som tradisjonell godkjenning, presenterer brukerne verifiserbare legitimasjonsbeskrivelser, men utstedes nå et sett med tokens i stedet for en økt-ID. De første legitimasjonene kan være standard brukernavn / passordpar, API-nøkler eller til og med tokens fra en annen tjeneste. (Stormpaths API Key Authentication Feature er et eksempel på dette.)

1.1. Hvorfor poletter?

Svært enkelt kan bruk av tokens i stedet for økt-IDer redusere serverbelastningen, effektivisere tillatelsesadministrasjon og gi bedre verktøy for å støtte en distribuert eller skybasert infrastruktur. I tilfelle av JWT oppnås dette primært gjennom den statsløse naturen til disse typer tokens (mer om det nedenfor).

Tokens tilbyr et bredt utvalg av applikasjoner, inkludert: Cross Site Request Forgery (CSRF) -beskyttelsesordninger, OAuth 2.0-interaksjoner, sesjons-IDer og (i informasjonskapsler) som autentiseringsrepresentasjoner. I de fleste tilfeller spesifiserer ikke standarder et bestemt format for tokens. Her er et eksempel på et typisk Spring Security CSRF-token i HTML-skjema:

Hvis du prøver å legge ut skjemaet uten riktig CSRF-token, får du et feilrespons, og det er nytteverdien av tokens. Ovennevnte eksempel er et "dumt" token. Dette betyr at det ikke er noen iboende betydning å hente fra selve symbolet. Dette er også der JWT-er gjør en stor forskjell.

2. Hva er i en JWT?

JWTs (uttalt "jots") er URL-sikre, kodede, kryptografisk signerte (noen ganger krypterte) strenger som kan brukes som tokens i en rekke applikasjoner. Her er et eksempel på en JWT som brukes som et CSRF-token:

I dette tilfellet kan du se at token er mye lenger enn i vårt forrige eksempel. Akkurat som vi så før, hvis skjemaet sendes inn uten token, får du feilrespons.

Så hvorfor JWT?

Ovennevnte token er kryptografisk signert og kan derfor bekreftes, og gir bevis for at det ikke er blitt manipulert. Også JWT er kodet med en rekke tilleggsinformasjon.

La oss se på anatomien til en JWT for bedre å forstå hvordan vi presser all denne godheten ut av den. Du har kanskje lagt merke til at det er tre forskjellige seksjoner atskilt med punktum (.):

OverskrifteyJhbGciOiJIUzI1NiJ9
NyttelasteyJqdGkiOiJlNjc4ZjIzMzQ3ZTM0MTBkYjdlNjg3Njc4MjNiMmQ3MCIsImlhdC

I6MTQ2NjYzMzMxNywibmJmIjoxNDY2NjMzMzE3LCJleHAiOjE0NjY2MzY5MTd9

Signaturrgx_o8VQGuDa2AqCHSgVOD5G68Ld_YYM7N7THmvLIKc

Hver seksjon er base64 URL-kodet. Dette sikrer at den kan brukes trygt i en URL (mer om dette senere). La oss se nærmere på hver seksjon hver for seg.

2.1. Overskriften

Hvis du base64 for å dekode toppteksten, får du følgende JSON-streng:

{"alg": "HS256"}

Dette viser at JWT ble signert med HMAC ved hjelp av SHA-256.

2.2. Nyttelasten

Hvis du dekoder nyttelasten, får du følgende JSON-streng (formatert for klarhet):

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

Innen nyttelasten, som du kan se, er det et antall nøkler med verdier. Disse nøklene kalles "krav" og JWT-spesifikasjonen har syv av disse spesifisert som "registrerte" krav. De er:

issUtsteder
underEmne
audPublikum
ekspUtløp
nbfIkke før
iatUtstedt kl
jtiJWT ID

Når du bygger en JWT, kan du legge inn eventuelle tilpassede krav du ønsker. Listen over representerer ganske enkelt kravene som er reservert både i nøkkelen som brukes og den forventede typen. Vår CSRF har en JWT-ID, en "Utstedt på" -tid, en "Ikke før" -tid og en utløpstid. Utløpstiden er nøyaktig ett minutt etter den utstedte tiden.

2.3. Signaturen

Til slutt opprettes signaturdelen ved å ta overskriften og nyttelasten sammen (med. I mellom) og føre den gjennom den spesifiserte algoritmen (HMAC ved bruk av SHA-256, i dette tilfellet) sammen med en kjent hemmelighet. Merk at hemmeligheten er alltid en byte-matrise, og skal ha en lengde som gir mening for algoritmen som brukes. Nedenfor bruker jeg en tilfeldig base64-kodet streng (for lesbarhet) som er konvertert til en byte-array.

Det ser slik ut i pseudokode:

computeHMACSHA256 (header + "." + nyttelast, base64DecodeToByteArray ("4pE8z3PBoHjnV1AhvGk + e8h2p + ShZpOnpr8cwHmMh1w ="))

Så lenge du vet hemmeligheten, kan du generere signaturen selv og sammenligne resultatet ditt med signaturdelen i JWT for å bekrefte at den ikke har blitt tuklet med. Teknisk sett kalles en JWT som er kryptografisk signert en JWS. JWT-er kan også krypteres og vil da bli kalt en JWE. (I praksis brukes begrepet JWT for å beskrive JWE og JWS.)

Dette bringer oss tilbake til fordelene ved å bruke en JWT som vårt CSRF-token. Vi kan bekrefte signaturen, og vi kan bruke informasjonen kodet i JWT for å bekrefte gyldigheten. Så ikke bare trenger strengrepresentasjonen til JWT å matche det som er lagret på serversiden, vi kan sikre at den ikke utløper bare ved å inspisere eksp krav. Dette sparer serveren fra å opprettholde ytterligere tilstand.

Vi har dekket mye bakken her. La oss dykke ned i noen kode!

3. Sett opp JJWT-opplæringen

JJWT (//github.com/jwtk/jjwt) er et Java-bibliotek som gir endring til JSON Web Token oppretting og bekreftelse. For alltid gratis og åpen kildekode (Apache License, versjon 2.0), ble den designet med et byggefokusert grensesnitt som skjuler det meste av kompleksiteten.

De primære operasjonene ved bruk av JJWT innebærer å bygge og analysere JWT. Vi vil se på disse operasjonene neste, så gå inn på noen utvidede funksjoner i JJWT, og til slutt vil vi se JWT-er i aksjon som CSRF-tokens i en Spring Security, Spring Boot-applikasjon.

Koden vist i de følgende avsnittene finner du her. Merk: Prosjektet bruker Spring Boot fra begynnelsen, da det er enkelt å samhandle med API-et det avslører.

For å bygge prosjektet, utfør følgende:

git clone //github.com/eugenp/tutorials.git cd tutorials / jjwt mvn clean install

En av de gode tingene med Spring Boot er hvor enkelt det er å fyre av en applikasjon. For å kjøre JJWT Fun-applikasjonen, gjør du bare følgende:

java -jar mål / *. krukke 

Det er ti sluttpunkter som er eksponert i dette eksempelprogrammet (jeg bruker httpie til å samhandle med applikasjonen. Det finnes her.)

http lokal vert: 8080
Tilgjengelige kommandoer (antar httpie - //github.com/jkbrzt/httpie): http // localhost: 8080 / Denne bruksmeldingen http // localhost: 8080 / static-builder bygger JWT fra hardkodede krav http POST // localhost: 8080 / dynamisk byggmester-generell krav-1 = verdi-1 ... [krav-n = verdi-n] bygg JWT fra bestått i krav (ved hjelp av generelle kravskart) http POST // localhost: 8080 / dynamisk-byggerspesifikt krav -1 = verdi-1 ... [claim-n = value-n] build JWT from passed in claims (ved bruk av spesifikke påstandsmetoder) http POST // localhost: 8080 / dynamic-builder-compress claim-1 = value-1 ... [claim-n = value-n] build DEFLATE komprimert JWT fra bestått i krav http // localhost: 8080 / parser? jwt = Analyse sendt i JWT http // localhost: 8080 / parser-enforce? jwt = Analyse bestått i JWT håndhever det 'iss' registrerte kravet og 'hasMotorcycle' tilpasset krav http // localhost: 8080 / get-secrets Vis signeringsnøklene som er i bruk. http // localhost: 8080 / refresh-secrets Generer nye signeringsnøkler og vis dem. http POST // localhost: 8080 / sett-hemmeligheter HS256 = base64-kodet-verdi HS384 = base64-kodet-verdi HS512 = base64-kodet-verdi Angi eksplisitt hemmeligheter som skal brukes i applikasjonen.

I avsnittene som følger vil vi undersøke hvert av disse endepunktene og JJWT-koden i håndtererne.

4. Bygg JWT med JJWT

På grunn av JJWTs flytende grensesnitt er etableringen av JWT i utgangspunktet en tretrinnsprosess:

  1. Definisjonen av tokens interne krav, som utsteder, emne, utløp og ID.
  2. Den kryptografiske signeringen av JWT (gjør det til en JWS).
  3. Komprimering av JWT til en URL-sikker streng, i henhold til JWT Compact Serialization regler.

Den endelige JWT vil være en tredelt base64-kodet streng, signert med den angitte signaturalgoritmen, og bruker den medfølgende nøkkelen. Etter dette punktet er symbolet klart til å bli delt med den andre parten.

Her er et eksempel på JJWT i aksjon:

String jws = Jwts.builder () .setIssuer ("Stormpath") .setSubject ("msilverman") .claim ("name", "Micah Silverman") .claim ("scope", "admins") // fre 24. juni 2016 15:33:42 GMT-0400 (EDT) .setIssuedAt (Date.from (Instant.ofEpochSecond (1466796822L))) // Lør 24. juni 2116 15:33:42 GMT-0400 (EDT) .setExpiration (Date.from (Instant.ofEpochSecond (4622470422L))) .signWith (SignatureAlgorithm.HS256, TextCodec.BASE64.decode ("Yn2kjibddFAWtnPJ2AFlL8WXmohJMCvigQggaEypa5E =")) .compact

Dette ligner veldig på koden i StaticJWTController.fixedBuilder metode for kodeprosjektet.

På dette punktet er det verdt å snakke om noen antimønstre relatert til JWT og signering. Hvis du noen gang har sett JWT-eksempler før, har du sannsynligvis møtt ett av disse signeringsmønstringsscenariene:

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

Noen av HS typesignaturalgoritmer tar et byte-utvalg. Det er praktisk for mennesker å lese for å ta en streng og konvertere den til et byte-utvalg.

Anti-mønster 1 ovenfor viser dette. Dette er problematisk fordi hemmeligheten svekkes av å være så kort, og den er ikke en byteoppstilling i sin opprinnelige form. Så, for å holde det lesbart, kan vi base64 kode byte-arrayet.

Imidlertid tar anti-mønster 2 ovenfor den base64-kodede strengen og konverterer den direkte til en byte-array. Hva som skal gjøres er å dekode base64-strengen tilbake til den opprinnelige byte-arrayen.

Nummer 3 ovenfor viser dette. Så hvorfor er denne også et antimønster? Det er en subtil grunn i dette tilfellet. Legg merke til at signaturalgoritmen er HS512. Byte-matrisen er ikke den maksimale lengden som HS512 kan støtte, noe som gjør det til en svakere hemmelighet enn hva som er mulig for den algoritmen.

Eksempelkoden inkluderer en klasse som heter Hemmelig tjeneste som sikrer at hemmeligheter med riktig styrke brukes for den gitte algoritmen. Ved applikasjonens oppstartstidspunkt opprettes et nytt sett med hemmeligheter for hver av HS-algoritmene. Det er endepunkter for å oppdatere hemmelighetene, samt for å eksplisitt sette hemmelighetene.

Hvis du har prosjektet som beskrevet ovenfor, kan du utføre følgende slik at JWT-eksemplene nedenfor samsvarer med svarene fra prosjektet ditt.

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

Nå kan du slå / statisk byggmester sluttpunkt:

http // localhost: 8080 / static-builder

Dette produserer en JWT som ser slik ut:

eyJhbGciOiJIUzI1NiJ9. eyJpc3MiOiJTdG9ybXBhdGgiLCJzdWIiOiJtc2lsdmVybWFuIiwibmFtZSI6Ik1pY2FoIFNpbHZlcm1hbiIsInNjb3BlIjoiYWRtaW5zIiwiaW2 kP0i_RvTAmI8mgpIkDFhRX3XthSdP-eqqFKGcU92ZIQ

Nå, hit:

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

Svaret har alle påstandene som vi inkluderte da vi opprettet JWT.

HTTP / 1.1 200 OK Innholdstype: applikasjon / json; charset = UTF-8 ... {"jws": {"body": {"exp": 4622470422, "iat": 1466796822, "iss": "Stormpath "," name ":" Micah Silverman "," scope ":" admins "," sub ":" msilverman "}," header ": {" alg ":" HS256 "}," signatur ":" kP0i_RvTAmI8mgpIkDFhRX3XthSdP-eqqFKGcU92ZIQ "}," status ":" SUKSESS "}

Dette er parsingsoperasjonen, som vi kommer inn på i neste avsnitt.

La oss nå nå et endepunkt som tar krav som parametere og bygger en tilpasset JWT for oss.

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

Merk: Det er en subtil forskjell mellom hasMotorcycle påstand og de andre påstandene. httpie antar at JSON-parametere er strenger som standard. For å sende rå JSON ved hjelp av httpie, bruker du := form i stedet for =. Uten det ville det underkaste seg “HasMotorcycle”: “true”, som ikke er det vi vil ha.

Her er utgangen:

POST / dynamic-builder-general HTTP / 1.1 Godta: application / json ... {"hasMotorcycle": true, "iss": "Stormpath", "sub": "msilverman"} HTTP / 1.1 200 OK Innholdstype: application / json; tegnsett = UTF-8 ... { "jwt": "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJzdWIiOiJtc2lsdmVybWFuIiwiaGFzTW90b3JjeWNsZSI6dHJ1ZX0.OnyDs-zoL3-rw1GaSl_KzZzHK9GoiNocu-YwZ_nQNZU", "status": "suksess"} 

La oss ta en titt på koden som støtter dette endepunktet:

@RequestMapping (value = "/ dynamic-builder-general", method = POST) public JwtResponse dynamicBuilderGeneric (@RequestBody Map claims) kaster UupportedEncodingException {String jws = Jwts.builder () .setClaims (claims) .signWith (SignatureAlgor, secretService.getHS256SecretBytes ()) .compact (); returner nye JwtResponse (jws); }

Linje 2 sørger for at den innkommende JSON automatisk blir konvertert til et Java Map, noe som er veldig nyttig for JJWT da metoden på linje 5 ganske enkelt tar Map og setter alle krav samtidig.

Så kort som denne koden er, trenger vi noe mer spesifikt for å sikre at påstandene som blir godkjent, er gyldige. Bruker .setClaims (Map-krav) metoden er praktisk når du allerede vet at påstandene representert på kartet er gyldige. Det er her typesikkerheten til Java kommer inn i JJWT-biblioteket.

For hvert av de registrerte kravene som er definert i JWT-spesifikasjonen, er det en tilsvarende Java-metode i JJWT som tar den spesifikke typen.

La oss treffe et annet endepunkt i eksemplet vårt og se hva som skjer:

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

Merk at vi har passert i et helt tall, 5, for "sub" -kravet. Her er utgangen:

POST / dynamisk-byggerspesifikk HTTP / 1.1 Godta: application / json ... {"hasMotorcycle": true, "iss": "Stormpath", "sub": 5} HTTP / 1.1 400 Forespørsel om dårlig forbindelse: lukk innhold- Type: application / json; charset = UTF-8 ... {"exceptionType": "java.lang.ClassCastException", "message": "java.lang.Integer kan ikke kastes til java.lang.String", "status ":" FEIL "}

Nå får vi et feilrespons fordi koden håndhever typen registrerte krav. I dette tilfellet, under må være en streng. Her er koden som støtter dette endepunktet:

@RequestMapping (value = "/ dynamic-builder-specific", method = POST) public JwtResponse dynamicBuilderSpecific (@RequestBody Map claims) kaster UnsupportedEncodingException {JwtBuilder builder = Jwts.builder (); claimss.forEach ((key, value) -> {switch (key) {case "iss": builder.setIssuer ((String) value); break; case "sub": builder.setSubject ((String) value); break ; case "aud": builder.setAudience ((String) value); 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) value); break; default: builder.claim (key, value);}}); builder.signWith (SignatureAlgorithm.HS256, secretService.getHS256SecretBytes ()); returner nye JwtResponse (builder.compact ()); }

Akkurat som før godtar metoden a Kart av krav som parameter. Denne gangen kaller vi imidlertid den spesifikke metoden for hvert av de registrerte krav som håndhever typen.

En forbedring av dette er å gjøre feilmeldingen mer spesifikk. Akkurat nå vet vi bare at et av våre påstander ikke er riktig type. Vi vet ikke hvilket krav som var feil, eller hva det skulle være. Her er en metode som vil gi oss en mer spesifikk feilmelding. Den håndterer også en feil i den gjeldende koden.

private tomrom sikreType (strengregistrert krav, objektverdi, klasse forventet type) {boolsk isCorrectType = forventetType.isInstance (verdi) || expectType == Long.class && value instanceof Integer; if (! isCorrectType) {String msg = "Forventet type:" + forventet Type.getCanonicalName () + "for registrert krav: '" + registrertKrav + "', men fikk verdi:" + verdi + "av typen:" + verdi. getClass (). getCanonicalName (); kaste ny JwtException (msg); }}

Linje 3 sjekker at den overførte verdien er av den forventede typen. Hvis ikke, a JwtException kastes med den spesifikke feilen. La oss ta en titt på dette i aksjon ved å ringe den samme samtalen som vi gjorde tidligere:

http -v POST localhost: 8080 / dynamic-builder-specific iss = Stormpath sub: = 5 hasMotorcycle: = true
POST / dynamisk-byggerspesifikk HTTP / 1.1 Godta: applikasjon / json ...Brukeragent: HTTPie / 0.9.3 {"hasMotorcycle": true, "iss": "Stormpath", "sub": 5} HTTP / 1.1 400 Dårlig forespørselstilkobling: lukk Content-Type: application / json; charset = UTF -8 ... {"exceptionType": "io.jsonwebtoken.JwtException", "message": "Forventet type: java.lang.Streng for registrert krav: 'sub', men fikk verdi: 5 av typen: java.lang .Integer "," status ":" FEIL "}

Nå har vi en veldig spesifikk feilmelding som forteller oss at under krav er feil.

La oss sirkle tilbake til den feilen i koden vår. Problemet har ingenting med JJWT-biblioteket å gjøre. Problemet er at JSON til Java Object mapper innebygd i Spring Boot er for smart for vårt eget beste.

Hvis det er en metode som godtar et Java-objekt, vil JSON-kartleggeren automatisk konvertere et passert antall som er mindre enn eller lik 2147483647 til en Java Heltall. På samme måte vil den automatisk konvertere et passert antall som er større enn 2147483647 til en Java Lang. For iat, nbf, og eksp krav fra en JWT, vi vil at vår sikreType-test skal bestå om det kartlagte objektet er et heltall eller et langt. Derfor har vi tilleggsklausulen for å avgjøre om den overførte verdien er riktig type:

 boolsk isCorrectType = expectType.isInstance (verdi) || expectType == Long.class && value instanceof Integer;

Hvis vi forventer en lang, men verdien er en forekomst av heltal, sier vi fortsatt at den er riktig type. Med en forståelse av hva som skjer med denne valideringen, kan vi nå integrere den i vår dynamicBuilderSpecific metode:

@RequestMapping (value = "/ dynamic-builder-specific", method = POST) public JwtResponse dynamicBuilderSpecific (@RequestBody Map claims) kaster UnsupportedEncodingException {JwtBuilder builder = Jwts.builder (); claimss.forEach ((key, value) -> {switch (key) {case "iss": ensureType (key, value, String.class); builder.setIssuer ((String) value); break; case "sub": sureType (nøkkel, verdi, String.class); builder.setSubject ((String) verdi); break; case "aud": sikre Type (key, verdi, String.class); builder.setAudience ((String) verdi); break ; sak "exp": sikre Type (nøkkel, verdi, Long.class); builder.setExpiration (Date.from (Instant.ofEpochSecond (Long.parseLong (value.toString ())))); break; case "nbf": sikreType (nøkkel, verdi, Long.class); builder.setNotBefore (Date.from (Instant.ofEpochSecond (Long.parseLong (value.toString ()))); break; case "iat": ensureType (key, value, Long.class); builder.setIssuedAt (Date.from (Instant.ofEpochSecond (Long.parseLong (value.toString ()))); break; case "jti": ensureType (key, value, String.class); builder .setId ((streng) verdi); pause; standard: builder.claim (nøkkel, verdi);}}); builder.signWith (SignatureAlgorithm.HS256, secretService.getHS256SecretBytes ()); returner nye JwtResponse (builder.compact ()); }

Merk: I all eksempelkoden i denne seksjonen signeres JWT-er med HMAC ved hjelp av SHA-256-algoritmen. Dette er for å holde eksemplene enkle. JJWT-biblioteket støtter 12 forskjellige signaturalgoritmer som du kan dra nytte av i din egen kode.

5. Analyse av JWT med JJWT

Vi så tidligere at kodeeksemplet vårt har et endepunkt for å analysere en JWT. Treffer dette endepunktet:

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

produserer dette svaret:

HTTP / 1.1 200 OK Content-Type: application / json; charset = UTF-8 ... {"claims": {"body": {"exp": 4622470422, "iat": 1466796822, "iss": "Stormpath "," name ":" Micah Silverman "," scope ":" admins "," sub ":" msilverman "}," header ": {" alg ":" HS256 "}," signatur ":" kP0i_RvTAmI8mgpIkDFhRX3XthSdP-eqqFKGcU92ZIQ "}," status ":" SUKSESS "}

De parser metoden for StaticJWTController klassen ser slik ut:

@RequestMapping (verdi = "/ parser", metode = GET) offentlig JwtResponse-parser (@RequestParam String jwt) kaster Ustøttet kodingException {Jws jws = Jwts.parser () .setSigningKeyResolver (secretService.getSigningKeyRes returner nye JwtResponse (jws); }

Linje 4 indikerer at vi forventer at den innkommende strengen skal være en signert JWT (en JWS). Og vi bruker den samme hemmeligheten som ble brukt til å signere JWT i å analysere den. Linje 5 analyserer påstandene fra JWT. Internt bekrefter den signaturen, og det vil gi et unntak hvis signaturen er ugyldig.

Legg merke til at i dette tilfellet passerer vi i en SigningKeyResolver snarere enn en nøkkel i seg selv. Dette er en av de mektigste aspektene ved JJWT. Overskriften til JWT indikerer algoritmen som ble brukt til å signere den. Vi må imidlertid bekrefte JWT før vi stoler på det. Det ser ut til å være en fangst 22. La oss se på SecretService.getSigningKeyResolver metode:

privat SigningKeyResolver signeringKeyResolver = ny SigningKeyResolverAdapter () {@Override offentlig byte [] resolSigningKeyBytes (JwsHeader header, Claims claims) {return TextCodec.BASE64.decode (secrets.get (header.getAlgorithm ())); }};

Bruke tilgangen til JwsHeader, Jeg kan inspisere algoritmen og returnere riktig byte-array for hemmeligheten som ble brukt til å signere JWT. Nå vil JJWT verifisere at JWT ikke har blitt tuklet med å bruke denne byte-arrayet som nøkkel.

Hvis jeg fjerner det siste tegnet i bestått i JWT (som er en del av signaturen), er dette svaret:

HTTP / 1.1 400 Dårlig forespørselstilkobling: lukk Innholdstype: applikasjon / json; charset = UTF-8 Dato: Man, 27. juni 2016 13:19:08 GMT Server: Apache-Coyote / 1.1 Transfer-Encoding: chunked {"exceptionType ":" io.jsonwebtoken.SignatureException "," message ":" JWT-signatur samsvarer ikke med lokal beregnet signatur. JWT-gyldighet kan ikke gjøres gjeldende og skal ikke stole på. "," status ":" FEIL "}

6. JWT-er i praksis: Vårsikkerhet CSRF-tokens

Selv om fokuset på dette innlegget ikke er vårsikkerhet, skal vi fordype oss litt her for å vise frem bruk av JJWT-biblioteket i den virkelige verden.

Forfalskning på tvers av sider er et sikkerhetsproblem hvor et ondsinnet nettsted lurer deg til å sende inn forespørsler til et nettsted du har etablert tillit til. En av de vanligste løsningene for dette er å implementere et synkroniseringstokenmønster. Denne tilnærmingen setter inn et token i webskjemaet, og applikasjonsserveren sjekker det innkommende tokenet mot depotet for å bekrefte at det er riktig. Hvis tokenet mangler eller er ugyldig, vil serveren svare med en feil.

Spring Security har innebygd synkroniseringstokenmønster. Enda bedre, hvis du bruker Spring Boot og Thymeleaf-malene, blir synkroniseringstokenet automatisk satt inn for deg.

Som standard er token som Spring Security bruker, et "dumt" token. Det er bare en serie bokstaver og tall. Denne tilnærmingen er bare bra, og den fungerer. I denne delen forbedrer vi grunnleggende funksjonalitet ved å bruke JWT som token. I tillegg til å verifisere at det innsendte tokenet er det som forventes, validerer vi JWT for å bevise at tokenet ikke er blitt manipulert med, og for å sikre at det ikke er utløpt.

For å komme i gang, skal vi konfigurere Spring Security ved hjelp av Java-konfigurasjon. Som standard krever alle baner autentisering, og alle POST-sluttpunkter krever CSRF-tokens. Vi kommer til å slappe av litt slik at det vi har bygget hittil fortsatt fungerer.

@Configuration offentlig klasse WebSecurityConfig utvider WebSecurityConfigurerAdapter {private String [] ignoreCsrfAntMatchers = {"/ dynamic-builder-compress", "/ dynamic-builder-general", "/ dynamic-builder-specific", "/ set-secrets"}; @ Override beskyttet ugyldig konfigurering (HttpSecurity http) kaster unntak {http .csrf () .ignoringAntMatchers (ignoreCsrfAntMatchers). Og (). AuthorizeRequests () .antMatchers ("/ **") .permitAll (); }}

Vi gjør to ting her. For det første sier vi at CSRF-tokens er det ikke kreves når du legger ut til REST API-endepunktene (linje 15). For det andre sier vi at uautentisert tilgang bør tillates for alle stier (linje 17 - 18).

La oss bekrefte at Spring Security fungerer slik vi forventer. Slå av appen og trykk denne url i nettleseren din:

// localhost: 8080 / jwt-csrf-form

Her er Thymeleaf-malen for denne visningen:

Dette er en veldig grunnleggende form som POSTER til samme endepunkt når den sendes inn. Legg merke til at det ikke er noen eksplisitt referanse til CSRF-tokens i skjemaet. Hvis du ser på kilden, vil du se noe sånt som:

Dette er all bekreftelse du trenger for å vite at Spring Security fungerer, og at Thymeleaf-malene automatisk setter inn CSRF-token.

For å gjøre verdien til en JWT, vil vi aktivere en tilpasset CsrfTokenRepository. Slik endres vår sikkerhetskonfigurasjon:

@Configuration public class WebSecurityConfig utvider WebSecurityConfigurerAdapter {@Autowired CsrfTokenRepository jwtCsrfTokenRepository; @ Override beskyttet ugyldig konfigurasjon (HttpSecurity http) kaster unntak {http .csrf () .csrfTokenRepository (jwtCsrfTokenRepository) .ignoringAntMatchers (ignoreCsrfAntMatchers) .and (). AuthorizeRequests () .antMatchers ("/ **). }}

For å koble til dette trenger vi en konfigurasjon som avslører en bønne som returnerer det tilpassede token-depotet. Her er konfigurasjonen:

@Configuration public class CSRFConfig {@Autowired SecretService secretService; @Bean @ConditionalOnMissingBean offentlig CsrfTokenRepository jwtCsrfTokenRepository () {returner nye JWTCsrfTokenRepository (secretService.getHS256SecretBytes ()); }}

Og her er vårt tilpassede lager (de viktige bitene):

offentlig klasse JWTCsrfTokenRepository implementerer CsrfTokenRepository {private static final Logger log = LoggerFactory.getLogger (JWTCsrfTokenRepository.class); privat byte [] hemmelighet; offentlig JWTCsrfTokenRepository (byte [] hemmelig) {this.secret = hemmelig; } @ Overstyr offentlig CsrfToken generer token (HttpServletRequest-forespørsel) {String id = UUID.randomUUID (). ToString (). Erstatt ("-", ""); Dato nå = ny dato (); Dato utløp = ny dato (System.currentTimeMillis () + (1000 * 30)); // 30 sekunder String token; prøv {token = Jwts.builder () .setId (id) .setIssuedAt (now) .setNotBefore (now) .setExpiration (exp) .signWith (SignatureAlgorithm.HS256, secret) .compact (); } fange (UnsupportedEncodingException e) {log.error ("Kan ikke opprette CSRf JWT: {}", e.getMessage (), e); token = id; } returner nytt DefaultCsrfToken ("X-CSRF-TOKEN", "_csrf", token); } @Override public void saveToken (CsrfToken token, HttpServletRequest request, HttpServletResponse response) {...} @Override public CsrfToken loadToken (HttpServletRequest request) {...}}

De generereToken metoden oppretter en JWT som utløper 30 sekunder etter at den er opprettet. Med denne rørleggerarbeidet på plass kan vi skyte opp applikasjonen igjen og se på kilden til / jwt-csrf-form.

Nå ser det skjulte feltet slik ut:

Huzzah! Nå er vårt CSRF-token en JWT. Det var ikke så vanskelig.

Dette er imidlertid bare halve puslespillet. Som standard lagrer Spring Security ganske enkelt CSRF-token og bekrefter at tokenet som sendes inn i et webskjema samsvarer med det som er lagret. Vi ønsker å utvide funksjonaliteten for å validere JWT og sørge for at den ikke har utløpt. For å gjøre det, legger vi til et filter. Slik ser vår Spring Security-konfigurasjon ut nå:

@Configuration offentlig klasse WebSecurityConfig utvider WebSecurityConfigurerAdapter {... @ Override-beskyttet ugyldig konfigurering (HttpSecurity http) kaster unntak {http .addFilterAfter (ny JwtCsrfValidatorFilter (), CsrfFilter.class) .csrfs (Ctrl. .and (). authorizeRequests () .antMatchers ("/ **") .permitAll (); } ...}

På linje 9 har vi lagt til et filter, og vi plasserer det i filterkjeden etter standard CsrfFilter. Så når filteret vårt treffes, vil JWT-token (som en helhet) allerede ha blitt bekreftet å være den riktige verdien lagret av Spring Security.

Her er JwtCsrfValidatorFilter (det er privat, da det er en indre klasse i vår vårsikkerhetskonfigurasjon):

privat klasse JwtCsrfValidatorFilter utvider OncePerRequestFilter {@Override beskyttet tomrom doFilterInternal (HttpServletRequest forespørsel, HttpServletResponse respons, FilterChain filterChain) kaster ServletException, IOException {// MERK: En reell implementering skal ha en ikke-cken request.getAttribute ("_ csrf"); hvis (// bare bryr seg om det er en POST "POST" .equals (request.getMethod ()) && // ignorerer hvis forespørselsbanen er i listen vår Arrays.binarySearch (ignoreCsrfAntMatchers, request.getServletPath ()) <0 && / / sørg for at vi har et token-token! = null) {// CsrfFilter sørget allerede for at token samsvarte. // Her vil vi sørge for at det ikke er utløpt, prøv {Jwts.parser () .setSigningKey (secret.getBytes ("UTF-8")) .parseClaimsJws (token.getToken ()); } fange (JwtException e) {// mest sannsynlig en ExpiredJwtException, men dette vil håndtere enhver request.setAttribute ("unntak", e); respons.setStatus (HttpServletResponse.SC_BAD_REQUEST); RequestDispatcher dispatcher = request.getRequestDispatcher ("utløpt-jwt"); dispatcher.forward (forespørsel, svar); }} filterChain.doFilter (forespørsel, svar); }}

Ta en titt på linje 23 på. Vi analyserer JWT som før. I dette tilfellet, hvis et unntak blir kastet, blir forespørselen videresendt til utløpt-jwt mal. Hvis JWT valideres, fortsetter behandlingen som normalt.

Dette lukker løkken for å overstyre standard Spring Security CSRF-tokenadferd med et JWT-token-depot og validator.

Hvis du fyrer opp appen, blar du til / jwt-csrf-form, vent litt mer enn 30 sekunder og klikk på knappen, du ser noe sånt som dette:

7. JJWT utvidede funksjoner

Vi avslutter JJWT-reisen med et ord om noen av funksjonene som strekker seg utover spesifikasjonen.

7.1. Håndheve krav

Som en del av analyseprosessen lar JJWT deg spesifisere påkrevde krav og verdier som påstandene skal ha. Dette er veldig nyttig hvis det er viss informasjon i JWT-ene dine som må være tilstede for at du skal kunne vurdere dem som gyldige. Det unngår mye forgreningslogikk for å validere krav manuelt. Her er metoden som serverer / parser-håndheve endepunkt for vårt prøveprosjekt.

@RequestMapping (verdi = "/ parser-enforce", metode = GET) offentlig JwtResponse parserEnforce (@RequestParam String jwt) kaster UupportedEncodingException {Jws jws = Jwts.parser () .requireIssuer ("Stormpath"). true) .setSigningKeyResolver (secretService.getSigningKeyResolver ()) .parseClaimsJws (jwt); returner nye JwtResponse (jws); }

Linje 5 og 6 viser syntaksen for registrerte krav samt tilpassede krav. I dette eksemplet vil JWT bli ansett som ugyldig hvis ISS-kravet ikke er tilstede eller ikke har verdien: Stormpath. Det vil også være ugyldig hvis det tilpassede hasMotorcycle-kravet ikke er tilstede eller ikke har verdien: true.

La oss først lage en JWT som følger den lykkelige banen:

http -v POST localhost: 8080 / dynamic-builder-specific \ iss = Stormpath hasMotorcycle: = true sub = msilverman
POST / dynamisk-byggerspesifikk HTTP / 1.1 Godta: application / json ... {"hasMotorcycle": true, "iss": "Stormpath", "sub": "msilverman"} HTTP / 1.1 200 OK Cache-Control: no-cache, no-butikken, max-age = 0, må revalidate Content-Type: application / json; charset = UTF-8 ... { "JWT": "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJoYXNNb3RvcmN5Y2xlIjp0cnVlLCJzdWIiOiJtc2lsdmVybWFuIn0.qrH-U6TLSVlHkZdYuqPRDtgKNr1RilFYQJtJbcgwhR0", "status ": "SUKSESS" }

La oss nå validere den JWT:

http -V localhost: 8080 / parser-håndheve JWT = eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJoYXNNb3RvcmN5Y2xlIjp0cnVlLCJzdWIiOiJtc2lsdmVybWFuIn0.qrH-U6TLSVlHkZdYuqPRDtgKNr1RilFYQJtJbcgwhR0?
? GET / parser-håndheve JWT = http -v localhost: 8080 / parser-håndheve JWT = eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJoYXNNb3RvcmN5Y2xlIjp0cnVlLCJzdWIiOiJtc2lsdmVybWFuIn0.qrH-U6TLSVlHkZdYuqPRDtgKNr1RilFYQJtJbcgwhR0 HTTP / 1.1 Godta: * / * ... HTTP / 1.1 200 OK Cache-Control: nei cache, no-store, max-age = 0, must-revalidate Content-Type: application / json; charset = UTF-8 ... {"jws": {"body": {"hasMotorcycle": true, "iss ":" Stormpath "," sub ":" msilverman "}," header ": {" alg ":" HS256 "}," signatur ":" qrH-U6TLSVlHkZdYuqPRDtgKNr1RilFYQJtJbcgwhR0 "}," status ":" SUCCESS "}

Så langt så bra. Nå, denne gangen, la oss la hasMotorsykkel være ute:

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

Denne gangen, hvis vi prøver å validere JWT:

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

vi får:

? GET / parser-håndheve JWT = http -v localhost: 8080 / parser-håndheve JWT = eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJzdWIiOiJtc2lsdmVybWFuIn0.YMONlFM1tNgttUYukDRsi9gKIocxdGAOLaJBymaQAWc HTTP / 1.1 Godta: * / * ... HTTP / 1.1 400 Bad Request Cache-Control: no-cache , no-store, max-age = 0, must-revalidate Connection: close Content-Type: application / json; charset = UTF-8 ... {"exceptionType": "io.jsonwebtoken.MissingClaimException", "message": "Forventet harMotorcykelkrav å være: sant, men var ikke tilstede i JWT-kravene.", "Status": "FEIL"}

Dette indikerer at kravet vårt om motorsykkel var forventet, men manglet.

La oss gjøre et eksempel til:

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

Denne gangen er det påkrevde kravet til stede, men det har feil verdi. La oss se resultatet av:

http -V localhost: 8080 / parser-håndheve JWT = eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJoYXNNb3RvcmN5Y2xlIjpmYWxzZSwic3ViIjoibXNpbHZlcm1hbiJ9.8LBq2f0eINB34AzhVEgsln_KDo-IyeM8kc-dTzSCr0c?
GET / parser-håndheve JWT = http -v localhost: 8080 / parser-håndheve JWT = eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJoYXNNb3RvcmN5Y2xlIjpmYWxzZSwic3ViIjoibXNpbHZlcm1hbiJ9.8LBq2f0eINB34AzhVEgsln_KDo-IyeM8kc-dTzSCr0c HTTP / 1.1 Godta: * / * ...HTTP / 1.1 400 Bad Request Cache-Control: no-cache, no-store, max-age = 0, must-revalidate Connection: close Content-Type: application / json; charset = UTF-8 ... {"exceptionType" : "io.jsonwebtoken.IncorrectClaimException", "message": "Forventet hasMotorcycle hevder å være: true, men var: false.", "status": "FEIL"}

Dette indikerer at vårt hasMotorcycle-krav var til stede, men hadde en verdi som ikke var forventet.

MissingClaimException og IncorrectClaimException er vennene dine når du håndhever påstander i JWT-ene dine, og en funksjon som bare JJWT-biblioteket har.

7.2. JWT-komprimering

Hvis du har mange krav på en JWT, kan den bli stor - så stor at den kanskje ikke passer i en GET-url i noen nettlesere.

La oss lage en stor JWT:

http -v POST localhost: 8080 / dynamic-builder-specific \ iss = Stormpath hasMotorcycle: = true sub = msilverman the = quick brown = fox jumped = over lat = hund \ et sted = over rainbow = way up = high and = the dreams = du drømte = om

Her er JWT som produserer:

eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJTdG9ybXBhdGgiLCJoYXNNb3RvcmN5Y2xlIjp0cnVlLCJzdWIiOiJtc2lsdmVybWFuIiwidGhlIjoicXVpY2siLCJicm93biI6ImZveCIsImp1bXBlZCI6Im92ZXIiLCJsYXp5IjoiZG9nIiwic29tZXdoZXJlIjoib3ZlciIsInJhaW5ib3ciOiJ3YXkiLCJ1cCI6ImhpZ2giLCJhbmQiOiJ0aGUiLCJkcmVhbXMiOiJ5b3UiLCJkcmVhbWVkIjoib2YifQ.AHNJxSTiDw_bWNXcuh-LtPLvSjJqwDvOOUcmkk7CyZA

Den sugeren er stor! La oss nå et litt annet endepunkt med de samme påstandene:

http -v POST localhost: 8080 / dynamic-builder-compress \ iss = Stormpath hasMotorcycle: = true sub = msilverman the = quick brown = fox jumped = over lat = hund \ et sted = over rainbow = way up = high and = the dreams = du drømte = om

Denne gangen får vi:

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

62 tegn kortere! Her er koden for metoden som brukes til å generere JWT:

@RequestMapping (value = "/ dynamic-builder-compress", method = POST) public JwtResponse dynamicBuildercompress (@RequestBody Map claims) kaster UupportedEncodingException {String jws = Jwts.builder () .setClaims (claims) .compressWith (CompressionCodecs.DEFL .signWith (SignatureAlgorithm.HS256, secretService.getHS256SecretBytes ()) .compact (); returner nye JwtResponse (jws); }

Legg merke til på linje 6 vi spesifiserer en komprimeringsalgoritme som skal brukes. Det er alt det er med det.

Hva med å analysere komprimerte JWT-er? JJWT-biblioteket oppdager automatisk komprimeringen og bruker den samme algoritmen til å dekomprimere:

GET /parser?jwt=eyJhbGciOiJIUzI1NiIsImNhbGciOiJERUYifQ.eNpEzkESwjAIBdC7sO4JegdXnoC2tIk2oZLEGB3v7s84jjse_AFe5FOikc5ZLRycHQ3kOJ0Untu8C43ZigyUyoRYSH6_iwWOyGWHKd2Kn6_QZFojvOoDupRwyAIq4vDOzwYtugFJg1QnJv-5sY-TVjQqN7gcKJ3f-j8c-6J-baDFhEN_uGn58XtnpfcHAAD__w.3_wc-2skFBbInk0YAQ96yGWwr8r1xVdbHn-uGPTFuFE HTTP / 1.1 Godta: * / * ... HTTP / 1.1 200 OK Cache-Control: no-cache, ingen -store, max-age = 0, must-revalidate Content-Type: application / json; charset = UTF-8 ... {"claims": {"body": {"and": "the", "brown" : "fox", "dreamed": "of", "dreams": "you", "hasMotorcycle": true, "iss": "Stormpath", "jumped": "over", "lat": "dog" , "rainbow": "way", "somewhere": "over", "sub": "msilverman", "the": "quick", "up": "high"}, "header": {"alg" : "HS256", "calg": "DEF"}, "signatur": "3_wc-2skFBbInk0YAQ96yGWwr8r1xVdbHn-uGPTFuFE"}, "status": "SUCCESS"}

Legg merke til kalg påstand i overskriften. Dette ble automatisk kodet inn i JWT, og det gir hint til parseren om hvilken algoritme som skal brukes til dekompresjon.

MERK: JWE-spesifikasjonen støtter komprimering. I en kommende utgivelse av JJWT-biblioteket vil vi støtte JWE og komprimerte JWE-er. Vi vil fortsette å støtte komprimering i andre typer JWT, selv om den ikke er spesifisert.

8. Token Tools for Java Devs

Mens hovedfokuset i denne artikkelen ikke var Spring Boot eller Spring Security, var det enkelt å demonstrere alle funksjonene som er diskutert i denne artikkelen ved å bruke disse to teknologiene. Du bør kunne bygge opp serveren og begynne å spille med de forskjellige endepunktene vi har diskutert. Bare trykk:

http // localhost: 8080

Stormpath er også glade for å ta med en rekke open source-utviklerverktøy til Java-fellesskapet. Disse inkluderer:

8.1. JJWT (Det vi har snakket om)

JJWT er et brukervennlig verktøy for utviklere for å opprette og verifisere JWT-er i Java. Som mange biblioteker Stormpath støtter, er JJWT helt gratis og åpen kildekode (Apache License, versjon 2.0), slik at alle kan se hva de gjør og hvordan de gjør det. Ikke nøl med å rapportere om problemer, foreslå forbedringer, og til og med sende inn noen kode!

8.2. jsonwebtoken.io og java.jsonwebtoken.io

jsonwebtoken.io er et utviklerverktøy vi opprettet for å gjøre det enkelt å dekode JWT. Bare lim inn en eksisterende JWT i riktig felt for å dekode topptekst, nyttelast og signatur. jsonwebtoken.io er drevet av nJWT, det reneste gratis og åpne kildekoden (Apache License, versjon 2.0) JWT-bibliotek for Node.js-utviklere. Du kan også se koden generert for en rekke språk på dette nettstedet. Nettstedet i seg selv er åpen kildekode og finner du her.

java.jsonwebtoken.io er spesielt for JJWT-biblioteket. Du kan endre topptekstene og nyttelasten i øvre høyre boks, se JWT generert av JJWT i øvre venstre boks, og se et utvalg av byggmester og parser Java-kode i de nedre boksene. Nettstedet i seg selv er åpen kildekode og finner du her.

8.3. JWT-inspektør

Det nye barnet på blokken, JWT Inspector, er en Chrome-utvidelse med åpen kildekode som lar utviklere inspisere og feilsøke JWT-er direkte i nettleseren. JWT-inspektøren vil oppdage JWT-er på nettstedet ditt (i informasjonskapsler, lokal lagring / øktlagring og overskrifter) og gjøre dem lett tilgjengelige via navigasjonsfeltet og DevTools-panelet.

9. JWT This Down!

JWT-er legger til litt intelligens til vanlige tokens. Evnen til å kryptografisk signere og verifisere, bygge inn utløpstider og kode annen informasjon i JWT setter scenen for virkelig statsløs øktadministrasjon. Dette har stor innvirkning på muligheten for å skalere applikasjoner.

På Stormpath bruker vi JWT for OAuth2-tokens, CSRF-tokens og påstander mellom mikrotjenester, blant annet bruksområder.

Når du begynner å bruke JWT-er, kan du aldri gå tilbake til fortidens stumme tokens. Har du spørsmål? Slå meg opp på @afitnerd på Twitter.


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