2013-12-18 50 views
0

我正在使用Play框架爲Instagram實時API開發消費者。但仍然無法正確執行x-hub簽名驗證。那麼,我們如何使用Java和Play框架來執行Instagram x-hub-signature驗證?如何在Java中驗證Instagram實時API x-hub-signature?

這裏是我當前的代碼:

  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裏面,我用這個下進行驗證代碼:

    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產生相同的結果。也許我應該提供原始二進制數據而不是字符串。

如果讓我們說我們需要一個JSON請求的原始二進制數據,然後我需要創建我的自定義BodyParser解析JSON請求原始二進制數據[5]

參考文獻:

[1- 4] http://pastebin.com/g4uuDwzn(SO不允許我發佈超過2個鏈接,所以我把所有的引用在這裏。這些鏈接包含在Ruby中,Python的簽名驗證和PHP)

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

[6]我的標準ne 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 <client_secret> <raw_response>.\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 

回答

1

最後我設法找到解決方案。對於Play Framework中的控制器,我們需要使用BodyParser.Raw,以便我們可以將原始數據(即字節數組)提取出有效載荷請求。

下面是在遊戲框架控制器代碼:

@BodyParser.Of(BodyParser.Raw.class) 
public static Result receiveRawInstaData(){ 
    Map<String, String[]> 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

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); 
    } 
} 

的方法verifySubscriptionPostRequestSignature代碼我jInstagram實施這一解決方案,這裏是鏈接源代碼:SubscriptionUtil