更新时间:2024-07-02 GMT+08:00
分享

接入鉴权

为保证SparkRTC的通信安全,当用户加入房间时,华为云SparkRTC服务需要对其进行接入鉴权。本章节主要介绍华为云SparkRTC接入鉴权的实现原理及鉴权签名的生成方法。

鉴权原理

华为云SparkRTC系统使用数字签名作为接入鉴权方式,需要在SDK加入房间时设置“signature”“ctime”“signature”为标识签名,由租户使用华为云SparkRTC提供的“app_key”“app_id”以及当前的“room_id”“user_id”“ctime”,按照华为SparkRTC的签名生成样例自行生成。具体参数说明请参见表1
//认证用的app_key和app_id硬编码至代码中或以明文形式存储会有极大风险。建议密文形式配置存储在文件或者环境变量中,使用时解密,以确保安全。本例以app_key和app_id存放至环境变量为例,运行前请先在本地环境中设置完成环境变量APP_KEY和APP_ID。
app_key =  System.getenv("APP_KEY");
app_id =  System.getenv("APP_ID");
signature = hmacSha256(app_key,(app_id + room_id + user_id + ctime))
表1 参数说明

参数

说明

app_key

华为云SparkRTC针对每个app生成的鉴权密钥,需要安全保存,谨防泄漏。

app_key的获取方法请参见如何获取密钥?

app_id

华为云SparkRTC生成的应用ID。

app_id请在实时音视频控制台的“应用管理”中获取。

room_id

租户自行创建的房间ID。

user_id

租户接入华为云SparkRTC系统的用户ID。

ctime

签名鉴权的过期时间。是系统当前UTC时间(unix时间戳)加上鉴权过期时间(推荐2小时,最长需要小于12小时)。单位为秒。

说明:

ctime为创建时间+过期时间,例如,当前时间为9点,鉴权过期时间为30分钟,则ctime为9点30分。即超过9点30分后,signature签名将失效。

建议租户构建自己的应用签名分发服务器,以防止“app_key”下沉到终端APP的过程中造成不必要的泄漏,鉴权原理如图1所示。

图1 鉴权原理

签名生成方法

您可以参考如下方法生成对应的签名。

  1. “app_id”“room_id”“user_id ”“ctime”拼接为一个字符串。
    1
    2
    long ctime = System.currentTimeMillis() / 1000 + 60 * 60;   //有效时间为1小时,单位是秒
    String content = app_id + "+" + room_id + "+" + user_id + "+" + ctime; 
    
  2. 使用“app_key”,通过HMAC-SHA256方式将字符串“content”进行加密,得到签名字符串。
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
        String signatureStr = hmacSha(appKey, content, "HmacSHA256");
        static String hmacSha(String KEY, String VALUE, String SHA_TYPE) {
            try {
                SecretKeySpec signingKey = new SecretKeySpec(KEY.getBytes("UTF-8"), SHA_TYPE);
                Mac mac = Mac.getInstance(SHA_TYPE);
                mac.init(signingKey);
                byte[] rawHmac = mac.doFinal(VALUE.getBytes("UTF-8"));
    
                byte[] hexArray = {
                        (byte) '0', (byte) '1', (byte) '2', (byte) '3',
                        (byte) '4', (byte) '5', (byte) '6', (byte) '7',
                        (byte) '8', (byte) '9', (byte) 'a', (byte) 'b',
                        (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f'
                };
                byte[] hexChars = new byte[rawHmac.length * 2];
                for (int j = 0; j < rawHmac.length; j++) {
                    int v = rawHmac[j] & 0xFF;
                    hexChars[j * 2] = hexArray[v >>> 4];
                    hexChars[j * 2 + 1] = hexArray[v & 0x0F];
                }
                return new String(hexChars);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
    

签名生成样例

为防止“app_key”密钥泄漏,建议您配置自己的应用签名分发服务器,向服务器传入“app_id”“room_id”“user_id”“ctime”后,由服务器返回签名。详细代码示例如下所示:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package com.xxx.xxx.utils;

import androidx.annotation.NonNull;

import com.alibaba.fastjson.JSON;
import com.huawei.rtcdemo.Constants;

import java.io.IOException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import okhttp3.Response;

public class SignatureUtil {
    private static final String TAG = "SignatureUtil";

    public interface onSignatureSuccess {
        void onSuccess(String signature);
    }

    public static void getSignature(String appid, String roomid, String userid, long ctime, String signatureKey, onSignatureSuccess callback) {
        if (Constants.RTC_SIGNATURE_USE_LOCAL) {
            getSignatureLocal(appid, roomid, userid, ctime, signatureKey, callback);
        } else {
            getSignatureRemote(appid, roomid, userid, ctime, callback);
        }
    }

    private static void getSignatureLocal(String appid, String roomid, String userid, long ctime, String signatureKey, @NonNull onSignatureSuccess callback) {
        String content = appid + "+" + roomid + "+" + userid + "+" + ctime; // here "+" is real char in content.
        String signature = SignatureUtil.hmacSha256(signatureKey, content);
        callback.onSuccess(signature);
    }

    private static void getSignatureRemote(String appid, String roomid, String userid, long ctime, @NonNull onSignatureSuccess callback) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpUtil httpUtil = new HttpUtil();
                // Constants.RTC_SIGNATURE_URL:带用户自己应用签名的分发服务器地址
                String url = Constants.RTC_SIGNATURE_URL + "?appid=" + appid + "&roomid=" + roomid + "&userid=" + userid + "&ctime=" + ctime;
                Response response = httpUtil.sendGetMethodWithHead(url, "X-AUTH-TOKEN", Constants.RTC_AUTH_TOKEN);
                if (response == null) {
                    return;
                }

                if (response.isSuccessful()) {
                    try {
                        String json = response.body().string();
                        String signature = JSON.parseObject(json).getString("signature");
                        callback.onSuccess(signature);
                    } catch (IOException e) {
                        LogUtil.e(TAG, "getSignature failed:" + e.getMessage());
                    }
                } else {
                    LogUtil.e(TAG, "getSignature failed!");
                }
            }
        }).start();
    }

    public static String hmacSha256(String KEY, String VALUE) {
        return hmacSha(KEY, VALUE, "HmacSHA256");
    }

    private static String hmacSha(String KEY, String VALUE, String SHA_TYPE) {
        try {
            SecretKeySpec signingKey = new SecretKeySpec(KEY.getBytes("UTF-8"), SHA_TYPE);
            Mac mac = Mac.getInstance(SHA_TYPE);
            mac.init(signingKey);
            byte[] rawHmac = mac.doFinal(VALUE.getBytes("UTF-8"));

            byte[] hexArray = {
                    (byte) '0', (byte) '1', (byte) '2', (byte) '3',
                    (byte) '4', (byte) '5', (byte) '6', (byte) '7',
                    (byte) '8', (byte) '9', (byte) 'a', (byte) 'b',
                    (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f'
            };
            byte[] hexChars = new byte[rawHmac.length * 2];
            for (int j = 0; j < rawHmac.length; j++) {
                int v = rawHmac[j] & 0xFF;
                hexChars[j * 2] = hexArray[v >>> 4];
                hexChars[j * 2 + 1] = hexArray[v & 0x0F];
            }
            return new String(hexChars);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

相关文档