[英]How can I validate the HMAC signature of a JWT token in pure Scala?
There's a few nice JWT token decoding libraries, but I have the feeling that I don't need any library because it should all boil down to base64 encode/decode and basic cryptography algorithms that can be found in the standard library. 有一些不错的JWT令牌解码库,但我觉得我不需要任何库,因为它应该归结为base64编码/解码和基本加密算法 ,可以在标准库中找到。
I found authentikat-jwt but it pulls in Apache common-codec and Json4s which I really don't want in my project: for example I already use another Json library! 我找到了authentikat-jwt,但它引入了Apache common-codec和Json4s,我真的不想在我的项目中使用:例如我已经使用了另一个Json库!
I found jwt-scala and pulls in all kind of Play framework deps.. Again, I'm just making a tiny microservice in Finagle! 我找到了jwt-scala并且引入了所有类型的Play框架。再次,我只是在Finagle中制作一个微小的微服务!
Over and over, I have the feeling all I need is a banana and what I get is a gorilla holding the banana. 一遍又一遍,我感觉我所需要的只是一根香蕉,我得到的是拿着香蕉的大猩猩 。
I finally ended up writing my own validator. 我终于写完了自己的验证器。 The only "dependency" in this snippet is my Json library that happens to be rapture-json .
这段代码中唯一的“依赖”是我的Json库恰好是rapture-json 。 You can totally replace it with your own library or even a regex (you only need to extract a field from a tiny Json object)
您可以完全用自己的库或甚至正则表达式替换它(您只需要从一个小的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
}
}
}
Usage 用法
The validate function supports base64 or string keys. validate函数支持base64或字符串键。 This is a demonstration of how to use it using the example token and signature found in this tutorial.
这是演示如何使用本教程中的示例标记和签名来使用它。 https://scotch.io/tutorials/the-anatomy-of-a-json-web-token
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))
Disclaimer / credits 免责声明/信用
I shamelessly ripped off some code from authentikat-jwt
and replaced the apache common codec code with standard Java version of the same stuff. 我无耻地从
authentikat-jwt
了一些代码,并用相同内容的标准Java版本替换了apache通用编解码器代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.