How to verify Instagram real-time API x-hub-signature in Java?

随声附和 提交于 2019-12-03 21:56:43

Finally I managed to find the solution. For the Controller in Play Framework, we need to use BodyParser.Raw so the we can extract the payload request as raw data, i.e. array of bytes.

Here's the code for the controller in Play Framework:

@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!");
}

And for the code for method verifySubscriptionPostRequestSignature in 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);
    }
}

I implemented this solution in jInstagram, here is the link to the source code: SubscriptionUtil

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!