2024/08/19 15:35:46
实现 HTTP 安全认证
本文介绍如何进行以下 HTTP 安全认证:
- HTTP 基本认证:易用,但安全性较弱。云端转码和观众端多码率都支持这种认证方式。
- HTTP HMAC (Hash-based Message Authentication Code) 认证:安全性较高。仅观众端多码率支持这种认证方式。
实现 HTTP 基本认证
云端转码和观众端多码率使用 HTTP 基本认证。本节介绍如何进行 HTTP 基本认证。
前提条件
已经从声网控制台获取客户 ID 和客户密钥,详见开通服务。
实现方法
参考 HTTP 基本认证实现。
实现 HTTP HMAC 认证
观众端多码率使用如下安全认证:
- HTTP 基本认证。易用,但安全性较弱。
- HTTP HMAC (Hash-based Message Authentication Code) 认证。安全性较高,推荐使用。
本节介绍如何实现 HTTP HMAC 认证。
发送请求时,你需要通过 HMAC-SHA256 算法生成一个签名,并在请求头部的 Authorization
字段传入签名。在生成签名的过程中,你需要用到以下声网账号的信息:
- 声网项目的 App ID,详见获取 App ID。
- 声网控制台 RESTful API 中提供的客户 ID 及客户密钥,详见生成客户 ID 和密钥。
示例代码
本节展示生成 Authorization
字段的示例代码。
- Python 示例
- Java 示例
Python
# -*- coding: utf-8 -*-
import os
import hmac
import base64
import datetime
from hashlib import sha256
import httplib
def execute_request_with_hmac():
# 你的声网项目的 App ID
# 需要设置环境变量 AGORA_APP_ID
appid = os.environ.get("AGORA_APP_ID")
# 客户 ID
# 需要设置环境变量 AGORA_CUSTOMER_USER_NAME
customer_username = os.environ.get("AGORA_CUSTOMER_USER_NAME")
# 客户密钥
# 需要设置环境变量 AGORA_CUSTOMER_SECRET
customer_secret = os.environ.get("AGORA_CUSTOMER_SECRET")
if not appid or not customer_username or not customer_secret:
print("Please check environments: AGORA_APP_ID, AGORA_CUSTOMER_USER_NAME, AGORA_CUSTOMER_SECRET")
return
# 请求包体
data = ""
# 请求域名
host = "api.sd-rtn.com"
# 请求方法,如下仅为示例,你可按需修改
req_metd = 'GET'
# 请求 endpoint,如下仅为示例,你可按需修改
path = "/v1/projects/{}/rtls/abr/config/codecs".format(appid)
# 获取请求的时间戳
# 后续请求头中会用到 date 字段
date = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
# 生成 HAMC 签名
body_sha256 = sha256(data.encode('utf-8')).digest()
body_sha256_base64 = base64.b64encode(body_sha256)
request_line = "{} {} {}".format(req_metd, path, "HTTP/1.1")
# 生成 digest
# 后续请求头中会用到 digest 字段
digest = "SHA-256={}".format(body_sha256_base64.decode("utf-8"))
signing_string = "host: {}\ndate: {}\n{}\ndigest: {}".format(
host, date, request_line, digest)
signature = base64.b64encode(hmac.new(customer_secret.encode("utf-8"),
signing_string.encode("utf-8"), sha256).digest())
# 生成 authorization
# 后续请求头中会用到 authorization 字段
authorization = 'hmac username="{}", algorithm="hmac-sha256", ' \
'headers="host date request-line digest", signature="{}"'.format(
customer_username, signature.decode("utf-8"))
# 创建连接
connection = httplib.HTTPSConnection(host, 443)
# 在请求头中填入之前生成的 date, digest, authorization
headers = {
"Date": date,
"Digest": digest,
"Authorization": authorization,
"Content-Type": "application/json"
}
# 执行请求
connection.request(req_metd, path, data, headers)
response = connection.getresponse()
# 打印响应状态码和内容
print("Status: {}".format(response.status))
print("Response: {}".format(response.read().decode('utf-8')))
# 关闭连接
connection.close()
if __name__ == "__main__":
execute_request_with_hmac()
Java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.TimeZone;
import java.util.Locale;
public class Main {
public static void main(String[] args) throws Exception {
// 你的声网项目的 App ID
// 需要设置环境变量 AGORA_APP_ID
String appId = System.getenv("AGORA_APP_ID");
// 客户 ID
// 需要设置环境变量 AGORA_CUSTOMER_USER_NAME
String customerUsername = System.getenv("AGORA_CUSTOMER_USER_NAME");
// 客户密钥
// 需要设置环境变量 AGORA_CUSTOMER_SECRET
String customerSecret = System.getenv("AGORA_CUSTOMER_SECRET");
if (appId == null || customerUsername == null || customerSecret == null) {
System.out.println("Please check environments: AGORA_APP_ID, AGORA_CUSTOMER_USER_NAME, AGORA_CUSTOMER_SECRET");
return;
}
// 请求域名
String host = "api.sd-rtn.com";
// 请求包体
String data = "";
// 请求方法,如下仅为示例,你可按需修改
String method = "GET";
// 请求 endpoint,如下仅为示例,你可按需修改
String path = "/v1/projects/" + appId + "/rtls/abr/config/codecs";
// 获取请求的时间戳
// 后续请求头中会用到 date 字段
String date = getCurrentUTCString();
// 生成 HAMC 签名
String bodySign = hashData(data);
// 生成 digest
// 后续请求头中会用到 digest 字段
String digest = "SHA-256=" + bodySign;
String reqline = method + " " + path + " HTTP/1.1";
String signingStr = "host: " + host + "\ndate: " + date + "\n" + reqline + "\ndigest: " + digest;
String sign = signData(signingStr, customerSecret);
// 生成 authorization
// 后续请求头中会用到 authorization 字段
String authorization = "hmac username=\"" + customerUsername + "\", ";
authorization += "algorithm=\"hmac-sha256\", ";
authorization += "headers=\"host date request-line digest\", ";
authorization += "signature=\"" + sign + "\"";
// 创建连接
URL url = new URL("https://" + host + path);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 执行请求
// 在请求头中填入之前生成的 date, digest, authorization
connection.setRequestMethod(method);
connection.setRequestProperty("Date", date);
connection.setRequestProperty("Digest", digest);
connection.setRequestProperty("Authorization", authorization);
connection.setRequestProperty("Content-Type", "application/json");
if (data != null && !data.isEmpty()) {
connection.setDoOutput(true);
byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
OutputStream outputStream = connection.getOutputStream();
outputStream.write(dataBytes);
outputStream.flush();
outputStream.close();
}
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
// 打印响应状态码和内容
System.out.println("Response: " + response.toString());
} else {
System.out.println("Unexpected response, statusCode: " + responseCode + ", statusMessage: " + connection.getResponseMessage());
}
// 关闭连接
connection.disconnect();
}
private static String hashData(String data) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hashBytes = digest.digest(data.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(hashBytes);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
private static String getCurrentUTCString() {
SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
return dateFormat.format(new Date());
}
private static String signData(String data, String secret) {
if (data == null || data.equals("")) {
return "";
}
try {
SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
Mac hmacSha256 = Mac.getInstance("HmacSHA256");
hmacSha256.init(secretKeySpec);
byte[] signature = hmacSha256.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(signature);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
下一步
开通服务、实现 HTTP HMAC 认证后,你可以进行如下操作:
- 参考实现观众端多码率了解实现流程。
- 参考多码率 RESTful API 说明进行集成。