寫這篇文檔主要是由於公司採用阿里雲的視頻播放進行APP集成,在阿里雲官方的文檔中文檔介紹不夠全,不少東西須要在網上查到,下面來介紹下用java實現阿里雲阿里雲防盜鏈生成及判斷阿里雲視頻是否正在播放,來刷新數據庫表中播放狀態
阿里雲官方文檔介紹播放鑑權URL爲:http://DomainName/Filename?au...,後端代碼主要生成auth_key來提供給app實現鑑權java
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; } }
根據實際狀況進行具體配置數據,配置後便可使用json
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; }