JWT предоставляет очень интересный способ представления заявок между приложениями, которые можно проверять и доверять. Моя цель здесь — показать небольшой пример для генерации и проверки токена с использованием превосходной библиотеки Nimbus JOSE + JWT .
обзор
Одно из лучших мест для знакомства — здесь . Вкратце, заимствуя материал из сайта jwt.io, заявки представлены в виде закодированного json в трех частях, разделенных точкой (.)
1
|
header.payload.signature |
Заголовок — это json, который содержит тип алгоритма, используемого для подписи контента (в данном случае RSA), который затем кодируется по URL и Base64:
1
2
3
|
{ "alg" : "RS512" } |
Полезная нагрузка — это json, содержащий все заявки, есть заявки, которые зарезервированы, но частные заявки также разрешены
1
2
3
4
5
6
7
|
{ "sub" : "samplesubject" , "name" : "John Doe" , "iss" : "sampleissueer" , "admin" : true , "exp" : 1451849539 } |
здесь «sub» (субъект), «iss» (эмитент) и «exp» (expiry) являются зарезервированными утверждениями, а «name» и «admin» являются частными утверждениями. Затем содержимое кодируется Base64Url.
Наконец, заголовок и полезная нагрузка вместе подписываются с использованием общего ключа или личного ключа, и подпись кодируется с помощью Base64 url и добавляется к токену с разделителем (.).
Генерация пары ключей
Мой пример основан на RSA, поэтому первым шагом является генерация пары ключей. JWK — это удобный способ хранить ключи как представление JSON, и библиотека Nimbus обеспечивает это:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import java.security.KeyPairGenerator import java.security.interfaces.{RSAPrivateKey, RSAPublicKey} import com.google.gson.{GsonBuilder, JsonElement, JsonParser} import com.nimbusds.jose.Algorithm import com.nimbusds.jose.jwk.{JWKSet, KeyUse, RSAKey} object JWKGenerator { def make(keySize: Integer, keyUse: KeyUse, keyAlg: Algorithm, keyId: String) = { val generator = KeyPairGenerator.getInstance( "RSA" ) generator.initialize(keySize) val kp = generator.generateKeyPair() val publicKey = kp.getPublic().asInstanceOf[RSAPublicKey] val privateKey = kp.getPrivate().asInstanceOf[RSAPrivateKey] new RSAKey.Builder(publicKey) .privateKey(privateKey) .keyUse(keyUse) .algorithm(keyAlg) .keyID(keyId) .build() } ... } |
Учитывая эту пару ключей, JWK может быть сгенерирован из этого с помощью Gson :
01
02
03
04
05
06
07
08
09
10
|
def generateJWKKeypair(rsaKey: RSAKey): JsonElement = { val jwkSet = new JWKSet(rsaKey) new JsonParser().parse(jwkSet.toJSONObject( false ).toJSONString) } def generateJWKJson(rsaKey: RSAKey): String = { val jsonElement = generateJWKKeypair(rsaKey) val gson = new GsonBuilder().setPrettyPrinting().create() gson.toJson(jsonElement) } |
Пример пары ключей на основе JWK выглядит следующим образом:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
{ "keys" : [ { "p" : "2_Fb6K50ayAsnnQl55pPegE_JNTeAjpDo9HThZPp6daX7Cm2s2fShtWuM8JBv42qelKIrypAAVOedLCM75VoRQ" , "kty" : "RSA" , "q" : "ye5BeGtkx_9z3V4ImX2Pfljhye7QT2rMhO8chMcCGI4JGMsaDBGUmGz56MHvWIlcqBcYbPXIWORidtMPdzp1wQ" , "d" : "gSjAIty6uDAm8ZjEHUU4wsJ8VVSJInk9iR2BSKVAAxJUQUrCVN---DKLr7tCKgWH0zlV0DjGtrfy7pO-5tcurKkK59489mOD4-1kYvnqSZmHC_zF9IrCyZWpOiHnI5VnJEeNwRz7EU8y47NjpUHWIaLl_Qsu6gOiku41Vpb14QE" , "e" : "AQAB" , "use" : "sig" , "kid" : "sample" , "qi" : "0bbcYShpGL4XNhBVrMI8fKUpUw1bWghgoyp4XeZe-EZ-wsc43REE6ZItCe1B3u14RKU2J2G57Mi9f_gGIP_FqQ" , "dp" : "O_qF5d4tQUl04YErFQ2vvsW4QoMKR_E7oOEHndXIZExxAaYefK5DayG6b8L5yxMG-nSncZ1D9ximjYvX4z4LQQ" , "alg" : "RS512" , "dq" : "jCy-eg9i-IrWLZc3NQW6dKTSqFEFffvPWYB7NZjIVa9TlUh4HmSd2Gnd2bu2oKlKDs1pgUnk-AAicgX1uHh2gQ" , "n" : "rX0zzOEJOTtv7h39VbRBoLPQ4dRutCiRn5wnd73Z1gF_QBXYkrafKIIvSUcJbMLAozRn6suVXCd8cVivYoq5hkAmcRiy0v7C4VuB1_Fou7HHoi2ISbwlv-kiZwTmXCn9YSHDBVivCwfMI87L2143ZfYUcNxNTxPt9nY6HJrtJQU" } ] } |
Генерация JWT
Теперь, когда у нас есть хороший пример пары ключей, загрузите закрытый и открытый ключи:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
import java.time.{LocalDateTime, ZoneOffset} import java.util.Date import com.nimbusds.jose._ import com.nimbusds.jose.crypto._ import com.nimbusds.jose.jwk.{JWKSet, RSAKey} import com.nimbusds.jwt.JWTClaimsSet.Builder import com.nimbusds.jwt._ object JwtSample { def main(args: Array[String]): Unit = { val jwkSet = JWKSet.load(JwtSample.getClass.getResource( "/sample.json" ).toURI.toURL) val jwk = jwkSet.getKeyByKeyId( "sample" ).asInstanceOf[RSAKey] val publicKey = jwk.toRSAPublicKey val privateKey = jwk.toRSAPrivateKey ... } |
Создайте полезную нагрузку, подпишите ее и сгенерируйте JWT:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
val claimsSetBuilder = new Builder() .subject( "samplesubject" ) .claim( "name" , "John Doe" ) .claim( "admin" , true ) .issuer( "sampleissueer" ) .expirationTime(Date.from(LocalDateTime.now().plusHours( 1 ).toInstant(ZoneOffset.UTC))) val signer = new RSASSASigner(privateKey) val signedJWT: SignedJWT = new SignedJWT( new JWSHeader(JWSAlgorithm.RS512), claimsSetBuilder.build()) signedJWT.sign(signer) val s = signedJWT.serialize() |
Потребитель этого JWT может прочитать полезную нагрузку и проверить ее, используя открытый ключ:
1
2
3
4
5
6
|
val cSignedJWT = SignedJWT.parse(s) val verifier = new RSASSAVerifier(publicKey) println(cSignedJWT.verify(verifier)) println(signedJWT.getJWTClaimsSet().getSubject()) |
Вывод
Этот образец полностью основан на образцах, представленных на сайте Nimbus JOSE + JWT , вам обязательно следует обратиться к сайту Nimbus, если вы заинтересованы в дальнейшем изучении этого.
- Мои образцы здесь
Ссылка: | JWT — Генерация и проверка токена — Образцы от нашего партнера JCG Биджу Кунджуммена в блоге all and sundry. |