账号体系
账号分配方式
KRTC提供两种账号使用方式,两种方式可以同时使用:
分配方式 | 描述 | 适用场景 |
---|---|---|
固定号码段 | 平台分配一段固定的号码给用户,调用方自行分配并管理号码 | 号码与固定用户绑定 |
匿名登录 | 平台自动分配匿名号码给来注册的用户,用户登出后自动释放号码 | 公开直播,观看方无需绑定固定号码 |
Token鉴权流程
KRTC使用基于签名算法校验机制,无需将用户的账号、密码同步到KRTC平台,保障了用户隐私的安全性。
调用方需根据下面给出的算法,在自己的业务服务器上生成AccessToken
,并传递给客户端。
Token的鉴权流程流程如下:
安全建议
调试时可以直接在客户端使用算法生成Token,但正式上线时,为了避免AppSecret泄露引发安全问题,应在服务端生成Token。
Token生成规则
Token生成需要使用AppKey、AppSecret、UserId及超时时间。
匿名登录时,UserId填空字符串。
超时时间单位为秒,为避免用户服务器和KRTC平台时间存在误差,有效期不应设置过短,默认为24小时。
Token生成代码
- Java
- Python3
- Node.js
- C++
- C#
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
public class AccessToken {
private String version;
private String appId;
private String appSecret;
public AccessToken(String appId, String appSecret) {
this.version = "1";
this.appId = appId;
this.appSecret = appSecret;
}
public String build(String userId, int expire) throws InvalidKeyException, NoSuchAlgorithmException {
SecretKeySpec keySpec = new SecretKeySpec(this.appSecret.getBytes(), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(keySpec);
String salt = String.valueOf(new SecureRandom().nextInt(99999999));
String expireTs = String.valueOf(System.currentTimeMillis() / 1000L + expire);
Base64.Encoder encoder = Base64.getEncoder();
byte[] signature = mac.doFinal((this.appId + userId + salt + expireTs).getBytes());
String token = String.join(":", this.version, this.appId, salt, expireTs, encoder.encodeToString(signature));
System.out.println("token : " + token);
return token;
}
}
import time
import hmac
import base64
import secrets
class AccessToken:
def __init__(self, app_id, app_secret = 86400):
self.__version = '1'
self.__app_id = app_id
self.__app_secret = app_secret
def build(self, user_id, expire):
salt = str(secrets.SystemRandom().randint(0, 99999999))
expire_ts = str(int(time.time()) + expire)
signature = hmac.new(self.__app_secret.encode(),
(self.__app_id + user_id + salt + expire_ts).encode(),
'sha256').digest()
token = ':'.join([self.__version, self.__app_id, salt, expire_ts, base64.b64encode(signature).decode()])
return token
import hmacSHA256 from 'crypto-js/hmac-sha256';
import Base64 from 'crypto-js/enc-base64';
class AccessToken {
constructor(app_id, app_secret) {
this.version = "1"
this.app_id = app_id;
this.app_secret = app_secret;
}
build(user_id, expire){
let that = this;
let salt = Math.floor(Math.random()*100000000);
let expire_ts = new Date().getTime() + expire;
const signature = Base64.stringify(hmacSHA256(that.app_id + user_id + salt + expire_ts, that.app_secret));
let token = this.version+":"+this.app_id+":"+salt+":"+expire_ts+":"+signature
return token
}
}
#pragma once
#include <time.h>
#include <string>
#include <sstream>
#include <string.h>
#include <iostream>
#include <sstream>
#include <openssl/hmac.h>
#define MIN_VALUE 0
#define MAX_VALUE 99999999
#define HMAC_SHA256_LENGTH 32
class AccessToken
{
public:
AccessToken(const std::string &app_id, const std::string &app_secret)
{
app_id_ = app_id;
app_secret_ = app_secret;
version_ = "1";
}
~AccessToken(){};
std::string Build(const char *user_id, int expire)
{
std::string salt = Salt();
time_t myt = time(NULL);
char chtime[1024] = {0};
uint64_t number = myt + expire;
snprintf(chtime, sizeof(chtime), "%lld", number);
std::string expire_ts = chtime;
std::string signature = GenerateSignature(app_secret_, app_id_, user_id, salt, expire_ts);
std::stringstream ss;
ss << version_ << ":" << app_id_ << ":" << salt << ":" << expire_ts << ":" << base64Encode(signature);
return ss.str();
}
std::string Salt()
{
srand((int)time(0));
char salt[1024] = {0};
int number = rand() % (MAX_VALUE - MIN_VALUE + 1) + MIN_VALUE;
snprintf(salt, sizeof(salt), "%d", number);
return salt;
}
std::string GenerateSignature(const std::string &secret, const std::string &appID, const std::string &userid, const std::string &salt, const std::string &expire_time)
{
std::stringstream ss;
ss << appID << userid << salt << expire_time;
return (HmacSign(secret, ss.str(), HMAC_SHA256_LENGTH));
}
std::string HmacSign(const std::string &secret, const std::string &message, uint32_t signSize)
{
if (secret.empty())
{
return "";
}
unsigned char md[EVP_MAX_MD_SIZE] = {0};
uint32_t md_len = 0;
HMAC(EVP_sha256(), (const unsigned char *)secret.data(),
secret.length(), (const unsigned char *)message.data(),
message.length(), &md[0], &md_len);
return std::string(reinterpret_cast<char *>(md), signSize);
}
char *base64_encode(const unsigned char *input, int length)
{
const char base64_chars[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/* http://www.adp-gmbh.ch/cpp/common/base64.html */
int i = 0, j = 0, s = 0;
unsigned char char_array_3[3], char_array_4[4];
int b64len = (length + 2 - ((length + 2) % 3)) * 4 / 3;
char *b64str = new char[b64len + 1];
while (length--)
{
char_array_3[i++] = *(input++);
if (i == 3)
{
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] =
((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] =
((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (i = 0; i < 4; i++)
b64str[s++] = base64_chars[char_array_4[i]];
i = 0;
}
}
if (i)
{
for (j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] =
((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] =
((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for (j = 0; j < i + 1; j++)
b64str[s++] = base64_chars[char_array_4[j]];
while (i++ < 3)
b64str[s++] = '=';
}
b64str[b64len] = '\0';
return b64str;
}
std::string base64Encode(const std::string &data)
{
char *r = base64_encode((const unsigned char *)data.data(), data.length());
std::string s(r);
delete[] r;
return s;
}
private:
std::string app_id_;
std::string app_secret_;
std::string version_;
};
using System;
using System.Text;
using System.Security.Cryptography;
class Token
{
const int MAX_RANDOM_NUMBER = 99999999;
public Token(string appId , string appSecret)
{
this.m_appId = appId;
this.m_appSecret = appSecret;
}
public string getToken(int expire = 7200, string userId = "")
{
var random = new Random();
string salt = random.Next(0, MAX_RANDOM_NUMBER).ToString();
Int64 epoch = (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
var expire_tick = epoch + expire;
string signature = m_appId + userId + salt + expire_tick.ToString();
var encoding = new System.Text.ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(m_appSecret);
byte[] messageBytes = encoding.GetBytes(signature);
using (var hmacsha256 = new HMACSHA256(keyByte))
{
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
return m_version + ":" + m_appId + ":" + salt + ":" + expire_tick.ToString() + ":" + Convert.ToBase64String(hashmessage);
}
}
string m_version = "1";
string m_appId;
string m_appSecret;
}