質問

Is there a Scala implementation of JWT or at least an example with Play? After having posted this question I searched further on the Internet and found some intros to JWT. Any suggestion would be really appreciated.

役に立ちましたか?

解決

I am using Nimbus-JOSE-JWT in a spray.io app and am quite happy with it. The object performing authentication extends HttpAuthenticator and if it finds a correct JWT it returns the token subject and related info, otherwise None (authentication fails). With Play2 you can implement HTTP Basic Auth with something like this. Regarding token setting/getting which I assume is of more interest to you:

First, create a private/public key pair (I used parts of this code). Create the authentication object that loads the keys on initialization from the filesystem.

Create a a com.nimbusds.jose.crypto.MACSigner and a com.nimbusds.jose.crypto.MACVerifier using these keys.

Whenever you want to set a key, FIRST encrypt it, THEN sign it. Encryption:

private def encrypt(subject: String) = {
   val header = new JWEHeader(JWEAlgorithm.RSA_OAEP, EncryptionMethod.A128GCM)
   val jwt = new EncryptedJWT(header, claimSet(subject))
   val encrypter = new RSAEncrypter(publicKey.asInstanceOf[java.security.interfaces.RSAPublicKey])
   jwt.encrypt(encrypter)
   jwt.serialize()
}

The claimSet method predictably returns a set of claims:

def claimSet(subject: String) = {
   val jwtClaims = new JWTClaimsSet()
   jwtClaims.setIssuer(Config.JWT.issuer)
   jwtClaims.setSubject(subject)
   jwtClaims.setJWTID(java.util.UUID.randomUUID().toString())
   jwtClaims
}

The publicKey property is the value returned from KeyFactory.getInstance("RSA").generatePublic.

Signing:

private def sign(jwt: String) = {
   val jwsObject = new JWSObject(new JWSHeader(JWSAlgorithm.HS256), new Payload(jwt))
   jwsObject.sign(Tokens.signer)
   jwsObject.serialize
}

Given the above, when you receive a key you need to verify the signature first, then decrypt it. For verification, first you try to parse it with com.nimbusds.jose.JWSObject.parse(my_token) and as long as it doesn't throw a ParseException you call verify on the JWSObject that parse returns, using as an argument the MACVerifier that you created earlier. If verify returns true, you only need to call getPayload.toString on the same JWSObject to get the verified payload.

To decrypt the verified payload you call com.nimbusds.jwt.EncryptedJWT.parse on it, then something like:

val decrypter = new RSADecrypter(privateKey.asInstanceOf[java.security.interfaces.RSAPrivateKey])
jwt.decrypt(decrypter)

privateKey is the value returned from KeyFactory.getInstance("RSA").generatePrivate.

You can then get the claim set with jwt.getJWTClaimsSet.

Finally, with regard to setting the Authorization header, I'm doing this on my AngularJS client using principles also mentioned in this post.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top