SDK开发说明
V3版本SDK对点播服务提供的所有API进行了封装,您可以通过点播API Explorer调试接口。同时在代码示例处,会生成各种语言的demo供您参考。您也可以使用“SDK代码示例调试”,直接调试代码。
媒资上传
当您需要使用服务端SDK上传本地媒资时,可参考《视频点播 API参考》中的应用示例1或应用示例2进行操作。其中,应用示例中对应的“创建媒资:上传方式”和“确认媒资上传”步骤,可参考SDK中的创建媒资:上传方式和确认媒资上传方法。在PUT媒资文件时,您可以使用HTTP PUT方式,将媒资文件PUT到对应的URL中即可。
生成鉴权URL
若您使用SDK时需要生成鉴权URL,可在点播控制台中使用Key防盗链算法生成,也可以参考以下Demo生成。
package AuthUrlDemo;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
class AuthUrlDemo {
// url是未带加密信息的原始播放url, key是在点播控制台配置的Key值
// 加密算法A
public static String createAuthInfoUrlByAlgorithmA(String url, String key, String method) {
try {
checkParam(url, key);
long timestamp = Instant.now().getEpochSecond();
String randUid = UUID.randomUUID().toString().replaceAll("-", "");
String uid = "0";
String tmpRandKey = timestamp + "-" + randUid + "-" + uid;
URL originUrl = new URL(url);
String originHashStr = originUrl.getPath() + "-" + tmpRandKey + "-" + key;
String hashStr = hashString(originHashStr, method);
String authInfo = "auth_key=" + tmpRandKey + "-" + hashStr;
return StringUtils.isEmpty(originUrl.getQuery()) ? url + "?" + authInfo : url + "&" + authInfo;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 加密算法B
public static String createAuthInfoUrlByAlgorithmB(String url, String key, String method) {
try {
checkParam(url, key);
URL originUrl = new URL(url);
String filePath = originUrl.getPath();
String dateStr = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm"));
String originHashStr = key + dateStr + filePath;
String hashStr = hashString(originHashStr, method);
return originUrl.getProtocol() + "://" + originUrl.getHost() + "/"
+ dateStr + "/" + hashStr + originUrl.getFile();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 加密算法C
public static String createAuthInfoUrlByAlgorithmC(String url, String key, String method) {
try {
checkParam(url, key);
URL originUrl = new URL(url);
String filePath = originUrl.getPath();
String hexTime = Long.toHexString(Instant.now().getEpochSecond()).toUpperCase(Locale.ENGLISH);
String originHashStr = key + filePath + hexTime;
String hashStr = hashString(originHashStr, method);
return originUrl.getProtocol() + "://" + originUrl.getHost() + "/" + hashStr + "/" + hexTime + originUrl.getFile();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// 加密算法D
public static String createAuthInfoUrlByAlgorithmD(String url, String key, String pliveDuration, String previewDuration) {
try {
isDigital("试看时长", previewDuration);
isDigital("伪直播开始时间", pliveDuration);
checkParam(url, key, previewDuration, pliveDuration);
String authArg = "";
URL originUrl = new URL(url);
String urlPath = originUrl.getPath();
String pathInUrl = urlPath.substring(0, urlPath.lastIndexOf("/") + 1);
String data = encodeUrl(pathInUrl) + "$" + getUtcTime();
if (previewDuration != null && !previewDuration.isEmpty()) {
data += "$" + previewDuration;
authArg = "&exper=" + previewDuration;
}
if (pliveDuration != null && !pliveDuration.isEmpty()) {
data += "$" + pliveDuration;
authArg = "&plive=" + pliveDuration;
}
String encryptInfo = aesCbcEncrypt(data, key, true);
String authInfoStr = "auth_info=" + URLEncoder.encode(encryptInfo, StandardCharsets.UTF_8);
if (url.contains("?")) {
return originUrl + "&" + authInfoStr + authArg;
}
return originUrl + "?" + authInfoStr + authArg;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static String createAuthInfoUrlByAlgorithmE(String url, String key, String pliveDuration, String previewDuration) {
try {
isDigital("试看时长", previewDuration);
isDigital("伪直播开始时间", pliveDuration);
checkParam(url, key, previewDuration, pliveDuration);
URL originUrl = new URL(url);
String urlPath = originUrl.getPath();
String currentTimestamp = String.valueOf(new Date().getTime() / 1000);
String authArg = "";
String authStr = key + urlPath + currentTimestamp;
if (previewDuration != null && !previewDuration.isEmpty()) {
authArg = "&exper=" + previewDuration;
authStr = authStr + previewDuration;
}
if (pliveDuration != null && !pliveDuration.isEmpty()) {
authArg = "&plive=" + pliveDuration + authArg;
authStr = authStr + pliveDuration;
}
authStr = sha256DigestAsHex(authStr);
authArg = "auth_key=" + authStr + "×tamp=" + currentTimestamp + authArg;
return url.contains("?") ? originUrl + "&" + authArg : originUrl + "?" + authArg;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private static void checkParam(String url, String key) {
if (StringUtils.isAnyEmpty(url, key)) {
throw new IllegalArgumentException("url or key is illegal");
}
}
private static void checkParam(String url, String key, String preview, String plive) {
if (StringUtils.isAnyEmpty(url, key)) {
throw new IllegalArgumentException("url or key is illegal");
}
if (StringUtils.isNoneEmpty(preview, plive)) {
throw new IllegalArgumentException("preview and plive cannot be enabled all ");
}
}
private static String aesCbcEncrypt(String data, String key, boolean hasPoint) throws Exception {
checkParam(data, key);
byte[] realKey = get128BitKey(key);
SecureRandom secureRand = new SecureRandom();
byte[] ivBytes = new byte[16];
secureRand.nextBytes(ivBytes);
if (hasPoint) {
return aesCbcEncrypt(data, ivBytes, realKey) + "." + bytesToHexString(ivBytes);
} else {
return aesCbcEncrypt(data, ivBytes, realKey) + bytesToHexString(ivBytes);
}
}
private static String aesCbcEncrypt(String data, byte[] ivBytes, byte[] key) throws Exception {
SecretKeySpec sk = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
if (ivBytes != null) {
cipher.init(Cipher.ENCRYPT_MODE, sk, new IvParameterSpec(ivBytes));
} else {
cipher.init(Cipher.ENCRYPT_MODE, sk);
}
return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)));
}
private static byte[] get128BitKey(String key) {
byte[] result = null;
if (key != null) {
result = new byte[16];
byte[] origin = key.getBytes();
System.arraycopy(origin, 0, result, 0, Math.min(origin.length, 16));
}
return result;
}
private static String encodeUrl(String str) {
try {
if (StringUtils.isNotEmpty(str)) {
StringBuilder encodeStr = new StringBuilder(32);
String[] tmpArray = str.split("/");
for (String s : tmpArray) {
encodeStr.append(URLEncoder.encode(s, StandardCharsets.UTF_8)).append("/");
}
return encodeStr.toString();
}
} catch (Exception e) {
throw new RuntimeException(String.format("Encode fail %s", e.getMessage()));
}
return str;
}
public static String sha256DigestAsHex(String plainText) {
MessageDigest messageDigest;
String encodeStr;
try {
messageDigest = MessageDigest.getInstance("SHA-256");
byte[] hash = messageDigest.digest(plainText.getBytes(StandardCharsets.UTF_8));
encodeStr = Hex.encodeHexString(hash);
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("Could not find MessageDigest with algorithm SHA-256", e);
}
return encodeStr;
}
private static String getUtcTime() {
SimpleDateFormat foo = new SimpleDateFormat("yyyyMMddHHmmss");
java.util.Calendar cal = java.util.Calendar.getInstance();
int zoneOffset = cal.get(java.util.Calendar.ZONE_OFFSET);
int dstOffset = cal.get(java.util.Calendar.DST_OFFSET);
cal.add(java.util.Calendar.MILLISECOND, -(zoneOffset + dstOffset));
return foo.format(new Date(cal.getTimeInMillis()));
}
private static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder();
if (src == null || src.length == 0) {
return null;
}
for (byte b : src) {
int v = b & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
private static void isDigital(String paramName, String value) throws Exception {
if (value != null && !value.isEmpty() && !value.matches("\\d+")) {
throw new Exception(paramName + "仅支持数字");
}
}
private static String hashString(String oriStr, String algorithm) {
return algorithm.equals("MD5") ? DigestUtils.md5Hex(oriStr.getBytes(StandardCharsets.UTF_8))
: sha256DigestAsHex(oriStr);
}
}
