2015-12-14 41 views
3

有一些很好的JWT令牌解码库,但我觉得我不需要任何库,因为它应该可以在标准库中找到所有boil down to base64 encode/decode and basic cryptography algorithms如何验证纯Scala中的JWT令牌的HMAC签名?

我找到了authentikat-jwt,但是它引入了Apache通用编解码器和Json4s,我真的不想在我的项目中使用它:例如我已经使用了另一个Json库!

我找到了jwt-scala,并且吸引了所有类型的Play框架代码。再次,我只是在Finagle中制作一个小小的微服务!

一遍又一遍,我感觉所有我需要的是一根香蕉,而我得到的是一只拿着香蕉的大猩猩

回答

1

我终于写了我自己的验证器。这个片段中唯一的“依赖”是我的Json库,恰巧是rapture-json。你完全可以用自己的库,或者是一个正则表达式替换它(你只需要从微小的JSON对象提取场)

/** 
    * Created by sscarduzio on 14/12/2015. 
    */ 
object JWTSignatureValidator { 

    import javax.crypto.Mac 
    import javax.crypto.spec.SecretKeySpec 


    def sign(algorithm: String, headerAndClaims: String, key: Array[Byte]): Array[Byte] = { 
    val algo = algorithm match { 
     case "HS256" => "HmacSHA256" 
     case "HS348" => "HmacSHA348" 
     case "HS512" => "HmacSHA512" 
     case "none" => "NONE" 
     case _ => throw new Exception("algo not found for verification of JWT: " + algorithm) 
    } 
    val scs = new SecretKeySpec(key, algo) 
    val mac = Mac.getInstance(algo) 
    mac.init(scs) 
    mac.doFinal(headerAndClaims.getBytes) 
    } 

    def decodeBase64(str: String): String = new String(new sun.misc.BASE64Decoder().decodeBuffer(str), "UTF-8") 

    def encodeBase64URLSafeString(bytes: Array[Byte]): String = { 
    // the "url safe" part in apache codec is just replacing the + with - and/with _ 
    val s = new sun.misc.BASE64Encoder().encode(bytes).map(c => if (c == '+') '-' else c).map(c => if (c == '/') '_' else c) 
    // We don't need the Base64 padding for JWT '=' 
    s.substring(0, s.size - 1) 
    } 

    import rapture.json._ 
    import jsonBackends.argonaut._ 

    def validate(jwt: String, key: String, keyIsBase64Encoded: Boolean): Boolean = { 

    jwt.split("\\.") match { 
     case Array(providedHeader, providedClaims, providedSignature) => 

     val headerJsonString = decodeBase64(providedHeader) 
     val algorithm = Json.parse(headerJsonString).alg.as[String] 
     val ourSignature = encodeBase64URLSafeString(sign(algorithm, providedHeader + "." + providedClaims, if (keyIsBase64Encoded) decodeBase64(key).getBytes("UTF-8") else key.getBytes("UTF-8"))) 
     providedSignature.contentEquals(ourSignature) 
     case _ => 
     false 
    } 
    } 
} 

使用

的验证功能支持的base64或字符串键。这是演示如何使用本教程中找到的示例标记和签名来使用它。 https://scotch.io/tutorials/the-anatomy-of-a-json-web-token

val token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ" 
val key = "c2VjcmV0=" // base64 of 'secret' 
println(validate(token, key, true)) 

免责声明/学分

我无耻地从authentikat-jwt扯掉一些代码,并用同样的东西标准的Java版本将取代阿帕奇共同编解码器代码。