写这篇文档主要是因为公司采用阿里云的视频播放进行APP集成,在阿里云官方的文档中文档介绍不够全,很多东西需要在网上查到,下面来介绍下用java实现阿里云阿里云防盗链生成及判断阿里云视频是否正在播放,来刷新数据库表中播放状态
阿里云官方文档介绍播放鉴权URL为:http://DomainName/Filename?au...,后端代码主要生成auth_key来提供给app实现鉴权
timestamp:失效时间,整形正数,固定长度 10,1970 年 1 月 1 日以来的秒数。用来控制失效时间,10 位整数,有效时间 1800s,这里是阿里云官方文档提供的失效时间,具体在阿里云直播上进行配置,(我们采取timestamp在生成主要是通过当前时间+阿里云配置的超时时间相加得出timestamp)
rand:阿里云官方默认为0
uid: 阿里云官方默认为0
md5hash:sstring = "URI-Timestamp-rand-uid-PrivateKey"(URI是用户的请求对象相对地址,不包含参数,如:/Filename),/video/standard-1444435200-0-0-addfvadeda生成防盗链代码
privateKey需要在阿里云进行配置
下面直接上代码
public class LiveAuthkeyUtils {
static String rand="0";
static String uid="0";
public static void main(String[] args) {
System.out.println(getPushUrl("/pwgl/cqStream09"));
System.out.println(getPlayUrl("/pwgl/cqStream09"));
}
//根据阿里云规则生成auth_key作为防盗链,直播
public static String getPushUrl(String url){
Date date=new Date();
long timestampdata=date.getTime()+ApplicationConfig.alimedia_timestamp;
String hashValue =url+"-"+timestampdata+"-"+rand+"-"+uid+"-"+ApplicationConfig.privateKey;
System.out.println(hashValue);
url="auth_key="+timestampdata+"-"+rand+"-"+uid+"-"+Md5Util.compute(hashValue);
return url;
}
//根据阿里云规则生成auth_key作为防盗链,播放
public static String getPlayUrl(String url){
Date date=new Date();
long timestampdata=date.getTime()+ApplicationConfig.alimedia_timestamp;
String hashValue =url+"-"+timestampdata+"-"+rand+"-"+uid+"-"+ApplicationConfig.privateKey;
String auth_key="auth_key="+timestampdata+"-"+rand+"-"+uid+"-"+Md5Util.compute(hashValue);
return auth_key;
}
}
阿里云查看是否正在推流及禁止直播推流代码,调用steamIsOnline方法传入参数streamName则可以查看是否正在推流传入参数为(上面"cqStream09")
public class LiveUtils {
/**
* 日志对象
*/
protected Logger logger = LoggerFactory.getLogger(getClass());
// 签名算法版本,目前版本是1.0
private static final String SIGNATURE_VERSION = "1.0";
// 签名方式,目前支持 HMAC-SHA1
private static final String SIGNATURE_METHOD = "HMACSHA1";
// API 版本号为日期形式:YYYY-MM-DD。本版本对应为:2016-11-01
private static final String VERSION = "2016-11-01";
// 请求类型(GET/POST)
private static final String REQUEST_METHOD_TYPE = "GET";
// 返回值类型(JSON/XML)
private static final String RET_FORMAT_TYPE = "JSON";
// 参数之间分隔符
private static final Character SEPARATOR = '&';
private static final String HOST = "https://live.aliyuncs.com";
/**
* 查询推流地址是否在推流
* @return
*/
public Boolean steamIsOnline(String streamName) {
logger.info("oooo 查询推流地址是否在推流");
//构建请求参数
Map<String, Object> params = Maps.newHashMap();
try {
//接口参数
params.put("Action", "DescribeLiveStreamsOnlineList");
params.put("DomainName", ApplicationConfig.ali_live_domain_name);
params.put("AppName", ApplicationConfig.ali_live_app_name);
//公共参数
buildPublicParams(params);
}catch (Exception e) {
logger.error("oooo 查询推流地址是否在推流, 参数构建出错", e);
}
//构建请求
String request = null;
try {
request = buildRequest(HOST, params, ApplicationConfig.alimedia_accessKeySecret);
} catch (UnsupportedEncodingException e) {
logger.error("oooo 查询推流地址是否在推流, 【UTF-8】编码方式不支持", e);
} catch (NoSuchAlgorithmException e) {
logger.error("oooo 查询推流地址是否在推流, 签名加密【{}】失败", SIGNATURE_METHOD, e);
} catch (InvalidKeyException e) {
logger.error("oooo 查询推流地址是否在推流, secretKey: 【{}】无效", ApplicationConfig.alimedia_accessKeySecret, e);
}
//发送请求
String result = "";
try {
result = send(request);
} catch (IOException e) {
logger.error("oooo 查询推流地址是否在推流, 请求接口失败", e);
}
//处理结果列表
boolean isContainSteamName = false; //是否包含推流名称
try {
JSONObject resultJson = JSONObject.parseObject(result);
JSONObject onlineInfo = resultJson.getJSONObject("OnlineInfo"); //正在推送的流信息
JSONArray liveStreamOnlineInfo = onlineInfo.getJSONArray("LiveStreamOnlineInfo");
for(Object obj : liveStreamOnlineInfo) {
JSONObject jsonObject = (JSONObject)obj;
String onlineStreamName = jsonObject.getString("StreamName"); //流名称
if(StringUtils.equalsIgnoreCase(streamName, onlineStreamName)) {
isContainSteamName = true;
break;
}
}
}catch (Exception e) {
logger.error("oooo 查询推流地址是否在推流, 结果集解析出错, result: {}", result, e);
}
return isContainSteamName;
}
/**
* 禁止直播流推送
* @param streamName
* @return
*/
public Boolean forbidLiveStream(String streamName) {
logger.info("oooo 禁止直播流推送, streamName: {}", streamName);
//构建请求参数
Map<String, Object> params = Maps.newConcurrentMap();
try {
//接口参数
params.put("Action", "ResumeLiveStream");
params.put("DomainName", ApplicationConfig.ali_live_domain_name);
params.put("AppName", ApplicationConfig.ali_live_app_name);
params.put("StreamName", streamName);
params.put("LiveStreamType", "publisher");//用于指定主播推流还是客户端拉流,目前支持 “publisher”(主播推送)
//公共参数
buildPublicParams(params);
}catch (Exception e) {
logger.error("oooo 禁止直播流推送, 参数构建出错", e);
return false;
}
//构建请求
String request;
try {
request = buildRequest(HOST, params, ApplicationConfig.alimedia_accessKeySecret);
} catch (UnsupportedEncodingException e) {
logger.error("oooo 禁止直播流推送, 【UTF-8】编码方式不支持", e);
return false;
} catch (NoSuchAlgorithmException e) {
logger.error("oooo 禁止直播流推送, 签名加密【{}】失败", SIGNATURE_METHOD, e);
return false;
} catch (InvalidKeyException e) {
logger.error("oooo 禁止直播流推送, secretKey: 【{}】无效", ApplicationConfig.alimedia_accessKeySecret, e);
return false;
}
//发送请求
try {
send(request);
} catch (IOException e) {
logger.error("oooo 禁止直播流推送, 请求接口失败", e);
return false;
}
return true;
}
/**
* 发送请求
* @param request
* @return
* @throws IOException
*/
private String send(String request) throws IOException {
HttpClient client = new HttpClient();
GetMethod method = new GetMethod(request);
method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(3, false));
int statusCode = client.executeMethod(method);
if (statusCode != HttpStatus.SC_OK) {
logger.error("oooo 阿里云接口请求失败: request: {}, {}", request, method.getStatusLine());
}
byte[] responseBody = method.getResponseBody();
return new String(responseBody);
}
/**
* 构建公共参数
* @param params
* @return
*/
private Map<String, Object> buildPublicParams(Map<String, Object> params) {
final String timestamp = ParameterHelper.getISO8601Time(new Date());
final String signatureNonce = new BigInteger(32, new SecureRandom()).toString(8);
params.put("Format", RET_FORMAT_TYPE);
params.put("SignatureMethod", "HMAC-SHA1");
params.put("Timestamp", timestamp);
params.put("AccessKeyId", ApplicationConfig.alimedia_accessKeyId);
params.put("SignatureNonce", signatureNonce);
params.put("Version", VERSION);
params.put("SignatureVersion", SIGNATURE_VERSION);
return params;
}
/**
* 构建请求
* @param host
* @param params
* @param secret
* @return
* @throws UnsupportedEncodingException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
private String buildRequest(String host, Map<String, Object> params, String secret) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
String paramsStr = "";
List<String> sortedKeys = new ArrayList<String>(params.keySet());
Collections.sort(sortedKeys);
for (String key : sortedKeys) {
paramsStr += URLEncoder.encode(key, CharEncoding.UTF_8) + "=" + URLEncoder.encode(String.valueOf(params.get(key)), CharEncoding.UTF_8) + SEPARATOR;
}
return host + "/?" + paramsStr + "Signature=" + buildSignature(REQUEST_METHOD_TYPE, params, (secret + SEPARATOR));
}
/**
* 构建签名
* @param method
* @param params
* @param secretKey
* @return
* @throws UnsupportedEncodingException
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
*/
private String buildSignature(String method, Map<String, Object> params, String secretKey) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
String paramsStr = "";
List<String> sortedKeys = new ArrayList<String>(params.keySet());
Collections.sort(sortedKeys);
for (String key : sortedKeys) {
paramsStr += SEPARATOR + popEncode(key) + '=' + popEncode(String.valueOf(params.get(key)));
}
String stringToSign = method + SEPARATOR + popEncode("/") + SEPARATOR + popEncode(paramsStr.substring(1, paramsStr.length()));
//按照 RFC2104 的定义,计算签名 HMAC 值
Mac mac = Mac.getInstance(SIGNATURE_METHOD);
mac.init(new SecretKeySpec(secretKey.getBytes(CharEncoding.UTF_8), SIGNATURE_METHOD));
byte[] rawHmac = mac.doFinal(stringToSign.getBytes(CharEncoding.UTF_8));
String sign = new Base64Encoder().encode(rawHmac);
return URLEncoder.encode(sign, CharEncoding.UTF_8);
}
/**
* 编码
* @param value
* @return
* @throws UnsupportedEncodingException
*/
private static String popEncode(String value) throws UnsupportedEncodingException {
return value != null ? URLEncoder.encode(value, CharEncoding.UTF_8).replace("+", "%20").replace("*", "%2A").replace("%7E", "~") : null;
}
}
根据实际情况进行具体配置数据,配置后即可使用
public class ApplicationConfig {
static {
Properties prop = new Properties();
InputStream in = LiveAuthkeyUtils.class.getClassLoader()
.getResourceAsStream("appconfig.properties");
try {
prop.load(in);
privateKey = prop.getProperty("play.privateKey").trim();
ali_live_domain_name = prop.getProperty("play.ali_live_domain_name").trim();
ali_live_app_name = prop.getProperty("play.ali_live_app_name").trim();
alimedia_accessKeySecret = prop.getProperty("play.alimedia_accessKeySecret").trim();
alimedia_accessKeyId = prop.getProperty("play.alimedia_accessKeyId").trim();
alimedia_timestamp = Integer.parseInt(prop.getProperty("play.alimedia_timestamp").trim());
} catch (IOException e) {
e.printStackTrace();
}
}
//阿里云播放域名
public static String ali_live_domain_name="";
//阿里云播放app名
public static String ali_live_app_name="";
//阿里云
public static String alimedia_accessKeyId="";
//阿里云 accessKeySecret
public static String alimedia_accessKeySecret="";
//阿里云播放鉴权私匙
public static String privateKey="";
//阿里云播放鉴权超时时间设置,在阿里云进行设置
public static Integer alimedia_timestamp=86400;
}