Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Shopify验证Scala中的webhook调用_Scala_Playframework 2.0_Shopify_Sha256 - Fatal编程技术网

Shopify验证Scala中的webhook调用

Shopify验证Scala中的webhook调用,scala,playframework-2.0,shopify,sha256,Scala,Playframework 2.0,Shopify,Sha256,我正在为ShopifyWebhook实现一个使用Play2调用的简单web服务。我想使用包含的“X-Shopify-Hmac-Sha256”头参数验证调用是否来自Shopify Shopify文档只包含一个Ruby和Php示例,我认为翻译起来并不难。我似乎在挣扎 下面是我的简单Scala shopify util对象: import play.api.mvc.Request import play.api.mvc.AnyContent import javax.crypt

我正在为ShopifyWebhook实现一个使用Play2调用的简单web服务。我想使用包含的“X-Shopify-Hmac-Sha256”头参数验证调用是否来自Shopify

Shopify文档只包含一个Ruby和Php示例,我认为翻译起来并不难。我似乎在挣扎

下面是我的简单Scala shopify util对象:

    import play.api.mvc.Request
    import play.api.mvc.AnyContent
    import javax.crypto.Mac
    import javax.crypto.spec.SecretKeySpec
    import play.api.Logger
    import javax.crypto.SecretKey
    import org.apache.commons.codec.binary.Base64

    object ShopifyUtils {
        def verifyWebhookCall(request : Request[AnyContent], secretKey: String) : Boolean = {

          if (!request.headers.get("X-Shopify-Hmac-Sha256").isDefined)
              false
          else
          {
            val headerHash = request.headers.get("X-Shopify-Hmac-Sha256").getOrElse("")
            val body = request.body.asJson.get.toString

            Logger.info("json '" + request.body.asJson.get.toString + "' = " + encode(secretKey, request.body.asJson.get.toString) );
            Logger.info("body '" + request.body.toString() + "' = " + encode(secretKey, request.body.toString) )

            Logger.info("headerHash " + headerHash);

            val calcHash = encode(secretKey, body)
            headerHash.equals(calcHash)
          }
        }

        def encode(key: String , data: String): String = {
          val sha256_HMAC = Mac.getInstance("HmacSHA256");
          val secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");
          sha256_HMAC.init(secret_key);

          return new String( Base64.encodeBase64( sha256_HMAC.doFinal( data.getBytes ) ) ).trim
        }
    }
我生成的哈希与Shopify发送的哈希不同

要么是我的共享密钥错误(我不知道这是怎么回事),要么是我没有像Shopify那样散列相同的内容(我尝试了各种
request.body
output格式)

非常感谢收到任何提示/指南/建议


Tim

只需阅读原始帖子正文,然后运行验证签名即可。通过将主体抓取为JSON并将其转换为字符串,您可能会巧妙地操纵我们发送给您的响应

下面是我如何为几个使用webhooks(ruby)的项目完成的:


感谢csaunders为我指明了正确的方向

我使用的是默认的BodyParser
AnyContent
,当请求的内容类型指定为“application/json”时,它会隐式地将响应主体转换为json

我必须修改控制器对象以指定“原始”BodyParser:

    import play.api._
    import play.api.libs.iteratee.Enumerator
    import play.api.mvc.SimpleResult
    import play.api.mvc.ResponseHeader
    import play.api.libs.json._
    import play.Application
    import play.api.mvc._

    import javax.crypto.Mac
    import javax.crypto.spec.SecretKeySpec
    import play.api.Logger
    import javax.crypto.SecretKey
    import org.apache.commons.codec.binary.Base64

    object Purchase extends Controller { 

      val shopifyAppSecretKey = "11111111111111111111111111111111"

      def processPurchase() = Action( parse.raw ) {request =>

        val bodyRaw = request.body.asBytes(3000).getOrElse(Array[Byte]())
        val calculatedHash = encodeByteArray(shopifyAppSecretKey, bodyRaw)
        val shopifyHash = request.headers.get("X-Shopify-Hmac-Sha256").getOrElse("")

        Logger.info("keys '" + shopifyHash + "' || '" + calculatedHash + "' " + calculatedHash.equals(shopifyHash))

        val json: JsValue = Json.parse( new String(bodyRaw) )

        Ok( "Ok" ).as(HTML)
      }

      def encodeByteArray(key: String , data: Array[Byte]): String = {
        val sha256_HMAC = Mac.getInstance("HmacSHA256");
        val secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");
        sha256_HMAC.init(secret_key);

        return new String( Base64.encodeBase64( sha256_HMAC.doFinal( data ) ) ).trim
      }
    }
使用“raw”BodyParser意味着您必须自己将字节数组转换为字符串,然后手动解析该字符串以获得json,但这不是真正的问题

现在一切都如期进行

谢谢


蒂姆

谢谢你。是的,你是对的,我得到的不是原始的请求主体,而是它的预解析版本。
    import play.api._
    import play.api.libs.iteratee.Enumerator
    import play.api.mvc.SimpleResult
    import play.api.mvc.ResponseHeader
    import play.api.libs.json._
    import play.Application
    import play.api.mvc._

    import javax.crypto.Mac
    import javax.crypto.spec.SecretKeySpec
    import play.api.Logger
    import javax.crypto.SecretKey
    import org.apache.commons.codec.binary.Base64

    object Purchase extends Controller { 

      val shopifyAppSecretKey = "11111111111111111111111111111111"

      def processPurchase() = Action( parse.raw ) {request =>

        val bodyRaw = request.body.asBytes(3000).getOrElse(Array[Byte]())
        val calculatedHash = encodeByteArray(shopifyAppSecretKey, bodyRaw)
        val shopifyHash = request.headers.get("X-Shopify-Hmac-Sha256").getOrElse("")

        Logger.info("keys '" + shopifyHash + "' || '" + calculatedHash + "' " + calculatedHash.equals(shopifyHash))

        val json: JsValue = Json.parse( new String(bodyRaw) )

        Ok( "Ok" ).as(HTML)
      }

      def encodeByteArray(key: String , data: Array[Byte]): String = {
        val sha256_HMAC = Mac.getInstance("HmacSHA256");
        val secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");
        sha256_HMAC.init(secret_key);

        return new String( Base64.encodeBase64( sha256_HMAC.doFinal( data ) ) ).trim
      }
    }