【问题标题】:How can I validate the HMAC signature of a JWT token in pure Scala?如何在纯 Scala 中验证 JWT 令牌的 HMAC 签名?
【发布时间】:2016-03-20 01:17:14
【问题描述】:

有一些不错的 JWT 令牌解码库,但我觉得我不需要任何库,因为它应该都是可以在标准库中找到的 boil down to base64 encode/decode and basic cryptography algorithms

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

我找到了jwt-scala 并引入了各种 Play 框架部门。再说一次,我只是在 Finagle 中制作一个微型微服务!

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

【问题讨论】:

    标签: scala playframework jwt twitter-finagle


    【解决方案1】:

    我终于编写了自己的验证器。这个 sn-p 中唯一的“依赖项”是我的 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 中抄袭了一些代码,并将 apache 通用编解码器代码替换为相同东西的标准 Java 版本。

    【讨论】:

      猜你喜欢
      • 2019-11-01
      • 2018-05-29
      • 2016-06-10
      • 2016-12-08
      • 1970-01-01
      • 2015-01-04
      • 2019-06-14
      • 2016-07-06
      • 2018-11-25
      相关资源
      最近更新 更多