# 实现 HTTP 安全认证 (/zh-CN/realtime-media/transcoding/build/http-auth)

> For AI agents: see the complete documentation index at [llms.txt](/llms.txt).

本文介绍如何进行以下 HTTP 鉴权：

- HTTP 基本认证：易用，但安全性较弱。云端转码和观众端多码率都支持这种认证方式。
- HTTP HMAC（Hash-based Message Authentication Code）鉴权：安全性较高。仅观众端多码率支持这种认证方式。

## 实现 HTTP 基本认证 [#实现-http-基本认证]

云端转码和观众端多码率使用 HTTP 基本认证。本节介绍如何进行 HTTP 基本认证。

### 前提条件 [#前提条件]

已经从声网控制台获取客户 ID 和客户密钥，详见[开通转码服务](/zh-CN/realtime-media/transcoding/build/enable-service)。

### 实现方法 [#实现方法]

参考 [HTTP 基本认证](/zh-CN/realtime-media/rtc/build/setup-and-access/http-basic-auth#生成方法)实现。

## 实现 HTTP HMAC 鉴权 [#实现-http-hmac-鉴权]

观众端多码率支持以下鉴权方式：

- [HTTP 基本认证](/zh-CN/realtime-media/transcoding/build/http-auth)。易用，但安全性较弱。
- HTTP HMAC（Hash-based Message Authentication Code）鉴权。安全性较高，推荐使用。

本节介绍如何实现 HTTP HMAC 鉴权。

发送请求时，你需要通过 HMAC-SHA256 算法生成签名，并在请求 Header 的 `Authorization` 字段中传入该签名。在生成签名的过程中，你需要用到以下声网账号的信息：

- 声网项目的 App ID，详见[获取 App ID](/zh-CN/realtime-media/transcoding/build/enable-service#获取-app-id)。
- 声网控制台 RESTful API 中提供的客户 ID 及客户密钥，详见[生成客户 ID 和密钥](/zh-CN/realtime-media/transcoding/build/enable-service#获取客户-id-和客户密钥)。

### 示例代码 [#示例代码]

本节展示生成 `Authorization` 字段的示例代码。

```python tab="Python 示例" tabGroup="language"
# -*- 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')

    # 生成 HMAC 签名
    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 tab="Java 示例" tabGroup="language"
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();
        // 生成 HMAC 签名
        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 鉴权后，你可以进行如下操作：

1. 参考[实现观众端多码率](/zh-CN/realtime-media/transcoding/build/enable-multiple-bitrate)了解实现流程。
2. 参考[多码率 RESTful API 说明](/zh-CN/api-reference/api-ref/cloud-transcoding/template-create)进行集成。
