事件回调签名计算
更新时间:2024-11-25
如果在事件回调设置中开启了签名设置,则VOD服务会在发送事件回调请求时,附加特定的header内容,开发者可以在回调接收端验证签名的合法性,如果通过签名算法计算的签名结果与请求header中的签名一致,则可以认为事件回调VOD服务发出的,否则可能是第三方恶意请求,开发者可以拒绝请求。
以下用一个例子来说明。
某用户在VOD开启了回调签名,签名密钥为qwer1234
,事件回调的URL为http://www.example.com/callback
,该用户的百度云账号ID为e95e33a028bd49dbb3e08f068dc975d5
。
VOD服务在发送的一个媒资上传完成事件回调请求大致如下:
POST /callback HTTP/1.1
accept: */*
content-length: 594
host: www.example.com
user-agent: AHC/2.0
vod-callback-auth-timestamp: 1731317262714
vod-callback-auth-token: 900dcab1a5227dbb47a0893d85c9447490c4d2ba6d13ca881886372e9ec2a8aa
vod-callback-auth-user: e95e33a028bd49dbb3e08f068dc975d5
{"eventId":"evt-ekkti4ep2mk0gedf","eventType":"MEDIA_UPLOAD_COMPLETE","eventTime":"2024-11-11T09:27:41Z","mediaUploadCompleteEvent":{"mediaId":"mda-ekkt369ihnhei80d","name":"test1","description":"","mediaType":"video","banSt
atus":"NORMAL","createTime":"2024-11-11T09:27:41Z","source":{"sourceType":"UPLOAD","sourceUrl":"https://vod.example.com/mda-ekkt369ihnhei80d/test1.mp4"}}}
可以注意到,有3个特殊的header:
vod-callback-auth-user
:用户百度云账号IDvod-callback-auth-timestamp
:VOD发送回调时的时间戳vod-callback-auth-token
:VOD计算的签名结果值
vod-callback-auth-token
的计算方法如下:
content = CONCAT('POST;', {callbackUrl}, ';', {body}, ';', {vod-callback-auth-timestamp}, ';', {vod-callback-auth-user})
vod-callback-auth-token = SHA256-HEX(token, content)
content是一个字符串拼接的结果,{callbackUrl}
是回调地址,{body}
是回调请求body进行json压缩后的字符串,{vod-callback-auth-timestamp}
和{vod-callback-auth-user}
是特定请求头,
SHA256-HEX是一个Hash算法,详见rfc4868。
为了便于用户开发,下面将给出Java实现的计算vod-callback-auth-token
的方法,其他语言版本可以自行实现。
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
public class VodEventCallbackTokenUtil {
private static final String HMAC_SHA256 = "HmacSHA256";
private static final Charset CHARSET_UTF8 = StandardCharsets.UTF_8;
public static String calculateToken(String signKey, String input) {
byte[] secretKeyBytes = signKey.getBytes(CHARSET_UTF8);
byte[] inputBytes = input.getBytes(CHARSET_UTF8);
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyBytes, HMAC_SHA256);
try {
Mac mac = Mac.getInstance(secretKeySpec.getAlgorithm());
mac.init(secretKeySpec);
mac.update(inputBytes, 0, inputBytes.length);
byte[] macBytes = mac.doFinal();
return String.valueOf(Hex.encodeHex(macBytes));
} catch (NoSuchAlgorithmException | InvalidKeyException ex) {
throw new RuntimeException(ex);
}
}
public static void main(String[] args) {
String callbackUrl = "http://www.example.com/callback";
String signKey = "qwer1234";
String userId = "e95e33a028bd49dbb3e08f068dc975d5";
String timestamp = "1731317262714";
String body = "{\"eventId\":\"evt-ekkti4ep2mk0gedf\",\"eventType\":\"MEDIA_UPLOAD_COMPLETE\",\"eventTime\":\"2024-11-11T09:27:41Z\","
+ "\"mediaUploadCompleteEvent\":{\"mediaId\":\"mda-ekkt369ihnhei80d\",\"name\":\"test1\",\"description\":\"\",\"mediaType\":\"video\",\"banSt\n"
+ "atus\":\"NORMAL\",\"createTime\":\"2024-11-11T09:27:41Z\",\"source\":{\"sourceType\":\"UPLOAD\",\"sourceUrl\":\"https://vod.example"
+ ".com/mda-ekkt369ihnhei80d/test1.mp4\"}}}";
String content = String.format("POST;%s;%s;%s;%s", callbackUrl, body, timestamp, userId);
String auth = calculateToken(signKey, content);
System.out.println(auth); // 输出结果 900dcab1a5227dbb47a0893d85c9447490c4d2ba6d13ca881886372e9ec2a8aa
}
}