如何用JavavalidationInstagram的实时API x-hub-signature?

我正在使用Play框架为Instagram实时API开发消费者。 但仍然无法正确执行x-hub-signaturevalidation。 那么,我们如何使用Java和Play框架执行Instagram x-hub-signaturevalidation呢?

这是我目前的代码:

  1. 在Play框架中,我使用此方法获取JSON有效内容:

    public static Result receiveInstaData(){ JsonNode json = request().body().asJson(); //obtain the x-hub-signature from the header //obtain the corresponding client secret VerificationResult verificationResult = SubscriptionUtil.verifySubscriptionPostSignature( clientSecret, json.toString(), xHubSignature); if(verificationResult.isSuccess()){ //do something } } 
  2. 然后在SubscriptionUtil ,我使用以下代码执行validation:

     public static VerificationResult verifySubscriptionPostSignature(String clientSecret, String rawJsonData, String xHubSignature) { SecretKeySpec keySpec; keySpec = new SecretKeySpec(clientSecret.getBytes("UTF-8"), HMAC_SHA1); Mac mac; mac = Mac.getInstance(HMAC_SHA1); mac.init(keySpec); byte[] result; result = mac.doFinal(rawJsonData.getBytes("UTF-8")); String encodedResult = Hex.encodeHexString(result); return new VerificationResult(encodedResult.equals(xHubSignature), encodedResult); } 

我创建了一个独立的Python脚本来复制instagram-python实现,它们都为同一个clientSecretjsonString产生相同的结果。 也许我应该提供原始二进制数据而不是String。

如果假设我们需要JSON请求的原始二进制数据,那么我需要创建自定义BodyParser来将JSON请求解析为原始二进制数据[5]

参考文献:

[1-4] http://pastebin.com/g4uuDwzn(SO不允许我发布超过2个链接,所以我把所有引用放在这里。链接包含Ruby,Python和PHP中的签名validation)

[5] https://groups.google.com/forum/#!msg/play-framework/YMQb6yeDH5o/jU8FD–yVPYJ

[6]我的独立python脚本:#! / usr / bin / env python

 import sys import hmac import hashlib hc_client_secret = "myclientsecret" hc_raw_response = "[{\"subscription_id\":\"1\",\"object\":\"user\",\"object_id\":\"1234\",\"changed_aspect\":\"media\",\"time\":1297286541},{\"subscription_id\":\"2\",\"object\":\"tag\",\"object_id\":\"nofilter\",\"changed_aspect\":\"media\",\"time\":1297286541}]" client_secret = hc_client_secret raw_response = hc_raw_response if len(sys.argv) != 3: print 'Usage verify_signature  .\nSince the inputs are invalid, use the hardcoded value instead!' else: client_secret = sys.argv[1] raw_response = sys.argv[2] print "client_secret = " + client_secret print "raw_response = " + raw_response digest = hmac.new(client_secret.encode('utf-8'), msg=raw_response.encode('utf-8'), digestmod=hashlib.sha1).hexdigest() print digest 

最后我设法找到了解决方案。 对于Play框架中的Controller,我们需要使用BodyParser.Raw以便我们可以将有效负载请求提取为原始数据,即字节数组。

这是Play Framework中控制器的代码:

 @BodyParser.Of(BodyParser.Raw.class) public static Result receiveRawInstaData(){ Map headers = request().headers(); RawBuffer jsonRaw = request().body().asRaw(); if(jsonRaw == null){ logger.warn("jsonRaw is null. Something is wrong with the payload"); return badRequest("Expecting serializable raw data"); } String[] xHubSignature = headers.get(InstaSubscriptionUtils.HTTP_HEADER_X_HUB_SIGNATURE); if(xHubSignature == null){ logger.error("Invalid POST. It does not contain {} in its header", InstaSubscriptionUtils.HTTP_HEADER_X_HUB_SIGNATURE); return badRequest("You are not Instagram!\n"); } String json; byte[] jsonRawBytes; jsonRawBytes = jsonRaw.asBytes(); json = new String(jsonRawBytes, StandardCharsets.UTF_8); try { String clientSecret = InstaSubscriptionUtils.getClientSecret(1); VerificationResult verificationResult = SubscriptionUtil.verifySubscriptionPostRequestSignature (clientSecret,jsonRawBytes, xHubSignature[0]); if(verificationResult.isSuccess()){ logger.debug("Signature matches!. Received signature: {}, calculated signature: {}", xHubSignature[0], verificationResult.getCalculatedSignature()); }else{ logger.error("Signature doesn't match. Received signature: {}, calculated signature: {}", xHubSignature[0], verificationResult.getCalculatedSignature()); return badRequest("Signature does not match!\n"); } } catch (InstagramException e) { logger.error("Instagram exception.", e); return internalServerError("Internal server error. We will attend to this problem ASAP!"); } logger.debug("Received xHubSignature: {}", xHubSignature[0]); logger.info("Sucessfully received json data: {}", json); return ok("OK!"); } 

并且为SubscriptionUtil方法verifySubscriptionPostRequestSignature的代码

 public static VerificationResult verifySubscriptionPostRequestSignature(String clientSecret, byte[] rawJsonData, String xHubSignature) throws InstagramException{ SecretKeySpec keySpec; keySpec = new SecretKeySpec(clientSecret.getBytes(StandardCharsets.UTF_8), HMAC_SHA1); Mac mac; try { mac = Mac.getInstance(HMAC_SHA1); mac.init(keySpec); byte[] result = mac.doFinal(rawJsonData); String encodedResult = Hex.encodeHexString(result); return new VerificationResult(encodedResult.equals(xHubSignature), encodedResult); } catch (NoSuchAlgorithmException e) { throw new InstagramException("Invalid algorithm name!", e); } catch (InvalidKeyException e){ throw new InstagramException("Invalid key: " + clientSecret, e); } } 

我在jInstagram中实现了这个解决方案,这里是源代码的链接: SubscriptionUtil