252 lines
13 KiB
C#
252 lines
13 KiB
C#
using System;
|
||
using System.IO;
|
||
using System.Text;
|
||
using System.Security.Cryptography;
|
||
using ComponentAce.Compression.Libs.zlib;
|
||
|
||
|
||
namespace YuanXuan.IM.Common.Helpers
|
||
{
|
||
public class TLSSigAPIv2
|
||
{
|
||
|
||
private readonly int sdkappid;
|
||
private readonly string key;
|
||
|
||
public TLSSigAPIv2(int sdkappid, string key)
|
||
{
|
||
this.sdkappid = sdkappid;
|
||
this.key = key;
|
||
}
|
||
|
||
/**
|
||
*【功能说明】用于签发 TRTC 和 IM 服务中必须要使用的 UserSig 鉴权票据
|
||
*
|
||
*【参数说明】
|
||
* userid - 用户id,限制长度为32字节,只允许包含大小写英文字母(a-zA-Z)、数字(0-9)及下划线和连词符。
|
||
* expire - UserSig 票据的过期时间,单位是秒,比如 86400 代表生成的 UserSig 票据在一天后就无法再使用了。
|
||
*/
|
||
public string genUserSig(string userid, int expire = 180 * 86400)
|
||
{
|
||
return genUserSig(userid, expire, null, false);
|
||
}
|
||
|
||
/**
|
||
*【功能说明】
|
||
* 用于签发 TRTC 进房参数中可选的 PrivateMapKey 权限票据。
|
||
* PrivateMapKey 需要跟 UserSig 一起使用,但 PrivateMapKey 比 UserSig 有更强的权限控制能力:
|
||
* - UserSig 只能控制某个 UserID 有无使用 TRTC 服务的权限,只要 UserSig 正确,其对应的 UserID 可以进出任意房间。
|
||
* - PrivateMapKey 则是将 UserID 的权限控制的更加严格,包括能不能进入某个房间,能不能在该房间里上行音视频等等。
|
||
* 如果要开启 PrivateMapKey 严格权限位校验,需要在【实时音视频控制台】=>【应用管理】=>【应用信息】中打开“启动权限密钥”开关。
|
||
*
|
||
*【参数说明】
|
||
* userid - 用户id,限制长度为32字节,只允许包含大小写英文字母(a-zA-Z)、数字(0-9)及下划线和连词符。
|
||
* roomid - 房间号,用于指定该 userid 可以进入的房间号
|
||
* expire - PrivateMapKey 票据的过期时间,单位是秒,比如 86400 生成的 PrivateMapKey 票据在一天后就无法再使用了。
|
||
* privilegeMap - 权限位,使用了一个字节中的 8 个比特位,分别代表八个具体的功能权限开关:
|
||
* - 第 1 位:0000 0001 = 1,创建房间的权限
|
||
* - 第 2 位:0000 0010 = 2,加入房间的权限
|
||
* - 第 3 位:0000 0100 = 4,发送语音的权限
|
||
* - 第 4 位:0000 1000 = 8,接收语音的权限
|
||
* - 第 5 位:0001 0000 = 16,发送视频的权限
|
||
* - 第 6 位:0010 0000 = 32,接收视频的权限
|
||
* - 第 7 位:0100 0000 = 64,发送辅路(也就是屏幕分享)视频的权限
|
||
* - 第 8 位:1000 0000 = 200,接收辅路(也就是屏幕分享)视频的权限
|
||
* - privilegeMap == 1111 1111 == 255 代表该 userid 在该 roomid 房间内的所有功能权限。
|
||
* - privilegeMap == 0010 1010 == 42 代表该 userid 拥有加入房间和接收音视频数据的权限,但不具备其他权限。
|
||
*/
|
||
|
||
public string genPrivateMapKey(string userid, int expire, uint roomid, uint privilegeMap)
|
||
{
|
||
byte[] userbuf = genUserBuf(userid, roomid, expire, privilegeMap, 0, "");
|
||
System.Console.WriteLine(userbuf);
|
||
return genUserSig(userid, expire, userbuf, true);
|
||
}
|
||
/**
|
||
*【功能说明】
|
||
* 用于签发 TRTC 进房参数中可选的 PrivateMapKey 权限票据。
|
||
* PrivateMapKey 需要跟 UserSig 一起使用,但 PrivateMapKey 比 UserSig 有更强的权限控制能力:
|
||
* - UserSig 只能控制某个 UserID 有无使用 TRTC 服务的权限,只要 UserSig 正确,其对应的 UserID 可以进出任意房间。
|
||
* - PrivateMapKey 则是将 UserID 的权限控制的更加严格,包括能不能进入某个房间,能不能在该房间里上行音视频等等。
|
||
* 如果要开启 PrivateMapKey 严格权限位校验,需要在【实时音视频控制台】=>【应用管理】=>【应用信息】中打开“启动权限密钥”开关。
|
||
*
|
||
*【参数说明】
|
||
* userid - 用户id,限制长度为32字节,只允许包含大小写英文字母(a-zA-Z)、数字(0-9)及下划线和连词符。
|
||
* roomstr - 房间号,用于指定该 userid 可以进入的房间号
|
||
* expire - PrivateMapKey 票据的过期时间,单位是秒,比如 86400 生成的 PrivateMapKey 票据在一天后就无法再使用了。
|
||
* privilegeMap - 权限位,使用了一个字节中的 8 个比特位,分别代表八个具体的功能权限开关:
|
||
* - 第 1 位:0000 0001 = 1,创建房间的权限
|
||
* - 第 2 位:0000 0010 = 2,加入房间的权限
|
||
* - 第 3 位:0000 0100 = 4,发送语音的权限
|
||
* - 第 4 位:0000 1000 = 8,接收语音的权限
|
||
* - 第 5 位:0001 0000 = 16,发送视频的权限
|
||
* - 第 6 位:0010 0000 = 32,接收视频的权限
|
||
* - 第 7 位:0100 0000 = 64,发送辅路(也就是屏幕分享)视频的权限
|
||
* - 第 8 位:1000 0000 = 200,接收辅路(也就是屏幕分享)视频的权限
|
||
* - privilegeMap == 1111 1111 == 255 代表该 userid 在该 roomid 房间内的所有功能权限。
|
||
* - privilegeMap == 0010 1010 == 42 代表该 userid 拥有加入房间和接收音视频数据的权限,但不具备其他权限。
|
||
*/
|
||
|
||
public string genPrivateMapKeyWithStringRoomID(string userid, int expire, string roomstr, uint privilegeMap)
|
||
{
|
||
byte[] userbuf = genUserBuf(userid, 0, expire, privilegeMap, 0, roomstr);
|
||
System.Console.WriteLine(userbuf);
|
||
return genUserSig(userid, expire, userbuf, true);
|
||
}
|
||
private string genUserSig(string userid, int expire, byte[] userbuf, bool userBufEnabled)
|
||
{
|
||
DateTime epoch = new DateTime(1970, 1, 1); // unix 时间戳
|
||
Int64 currTime = (Int64)(DateTime.UtcNow - epoch).TotalMilliseconds / 1000;
|
||
|
||
string base64UserBuf;
|
||
string jsonData;
|
||
if (true == userBufEnabled)
|
||
{
|
||
base64UserBuf = Convert.ToBase64String(userbuf);
|
||
string base64sig = HMACSHA256(userid, currTime, expire, base64UserBuf, userBufEnabled);
|
||
// 没有引入 json 库,所以这里手动进行组装
|
||
jsonData = String.Format("{{"
|
||
+ "\"TLS.ver\":" + "\"2.0\","
|
||
+ "\"TLS.identifier\":" + "\"{0}\","
|
||
+ "\"TLS.sdkappid\":" + "{1},"
|
||
+ "\"TLS.expire\":" + "{2},"
|
||
+ "\"TLS.time\":" + "{3},"
|
||
+ "\"TLS.sig\":" + "\"{4}\","
|
||
+ "\"TLS.userbuf\":" + "\"{5}\""
|
||
+ "}}", userid, sdkappid, expire, currTime, base64sig, base64UserBuf);
|
||
}
|
||
else
|
||
{
|
||
// 没有引入 json 库,所以这里手动进行组装
|
||
string base64sig = HMACSHA256(userid, currTime, expire, "", false);
|
||
jsonData = String.Format("{{"
|
||
+ "\"TLS.ver\":" + "\"2.0\","
|
||
+ "\"TLS.identifier\":" + "\"{0}\","
|
||
+ "\"TLS.sdkappid\":" + "{1},"
|
||
+ "\"TLS.expire\":" + "{2},"
|
||
+ "\"TLS.time\":" + "{3},"
|
||
+ "\"TLS.sig\":" + "\"{4}\""
|
||
+ "}}", userid, sdkappid, expire, currTime, base64sig);
|
||
}
|
||
|
||
byte[] buffer = Encoding.UTF8.GetBytes(jsonData);
|
||
return Convert.ToBase64String(CompressBytes(buffer))
|
||
.Replace('+', '*').Replace('/', '-').Replace('=', '_');
|
||
}
|
||
public byte[] genUserBuf(string account, uint dwAuthID, int dwExpTime, uint dwPrivilegeMap, uint dwAccountType, string roomStr)
|
||
{
|
||
int length = 1 + 2 + account.Length + 20;
|
||
int offset = 0;
|
||
if (roomStr.Length > 0)
|
||
length = length + 2 + roomStr.Length;
|
||
byte[] userBuf = new byte[length];
|
||
|
||
if (roomStr.Length > 0)
|
||
userBuf[offset++] = 1;
|
||
else
|
||
userBuf[offset++] = 0;
|
||
|
||
userBuf[offset++] = (byte)((account.Length & 0xFF00) >> 8);
|
||
userBuf[offset++] = (byte)(account.Length & 0x00FF);
|
||
|
||
byte[] accountByte = System.Text.Encoding.UTF8.GetBytes(account);
|
||
accountByte.CopyTo(userBuf, offset);
|
||
offset += account.Length;
|
||
|
||
//dwSdkAppid
|
||
userBuf[offset++] = (byte)((sdkappid & 0xFF000000) >> 24);
|
||
userBuf[offset++] = (byte)((sdkappid & 0x00FF0000) >> 16);
|
||
userBuf[offset++] = (byte)((sdkappid & 0x0000FF00) >> 8);
|
||
userBuf[offset++] = (byte)(sdkappid & 0x000000FF);
|
||
|
||
//dwAuthId
|
||
userBuf[offset++] = (byte)((dwAuthID & 0xFF000000) >> 24);
|
||
userBuf[offset++] = (byte)((dwAuthID & 0x00FF0000) >> 16);
|
||
userBuf[offset++] = (byte)((dwAuthID & 0x0000FF00) >> 8);
|
||
userBuf[offset++] = (byte)(dwAuthID & 0x000000FF);
|
||
|
||
//time_t now = time(0);
|
||
//uint32_t expire = now + dwExpTime;
|
||
long expire = dwExpTime + (long)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
|
||
userBuf[offset++] = (byte)((expire & 0xFF000000) >> 24);
|
||
userBuf[offset++] = (byte)((expire & 0x00FF0000) >> 16);
|
||
userBuf[offset++] = (byte)((expire & 0x0000FF00) >> 8);
|
||
userBuf[offset++] = (byte)(expire & 0x000000FF);
|
||
|
||
//dwPrivilegeMap
|
||
userBuf[offset++] = (byte)((dwPrivilegeMap & 0xFF000000) >> 24);
|
||
userBuf[offset++] = (byte)((dwPrivilegeMap & 0x00FF0000) >> 16);
|
||
userBuf[offset++] = (byte)((dwPrivilegeMap & 0x0000FF00) >> 8);
|
||
userBuf[offset++] = (byte)(dwPrivilegeMap & 0x000000FF);
|
||
|
||
//dwAccountType
|
||
userBuf[offset++] = (byte)((dwAccountType & 0xFF000000) >> 24);
|
||
userBuf[offset++] = (byte)((dwAccountType & 0x00FF0000) >> 16);
|
||
userBuf[offset++] = (byte)((dwAccountType & 0x0000FF00) >> 8);
|
||
userBuf[offset++] = (byte)(dwAccountType & 0x000000FF);
|
||
|
||
if (roomStr.Length > 0)
|
||
{
|
||
userBuf[offset++] = (byte)((roomStr.Length & 0xFF00) >> 8);
|
||
userBuf[offset++] = (byte)(roomStr.Length & 0x00FF);
|
||
|
||
byte[] roomStrByte = System.Text.Encoding.UTF8.GetBytes(roomStr);
|
||
roomStrByte.CopyTo(userBuf, offset);
|
||
offset += roomStr.Length;
|
||
}
|
||
return userBuf;
|
||
}
|
||
private static byte[] CompressBytes(byte[] sourceByte)
|
||
{
|
||
MemoryStream inputStream = new MemoryStream(sourceByte);
|
||
Stream outStream = CompressStream(inputStream);
|
||
byte[] outPutByteArray = new byte[outStream.Length];
|
||
outStream.Position = 0;
|
||
outStream.Read(outPutByteArray, 0, outPutByteArray.Length);
|
||
return outPutByteArray;
|
||
}
|
||
|
||
private static Stream CompressStream(Stream sourceStream)
|
||
{
|
||
MemoryStream streamOut = new MemoryStream();
|
||
ZOutputStream streamZOut = new ZOutputStream(streamOut, zlibConst.Z_DEFAULT_COMPRESSION);
|
||
CopyStream(sourceStream, streamZOut);
|
||
streamZOut.finish();
|
||
return streamOut;
|
||
}
|
||
|
||
public static void CopyStream(System.IO.Stream input, System.IO.Stream output)
|
||
{
|
||
byte[] buffer = new byte[2000];
|
||
int len;
|
||
while ((len = input.Read(buffer, 0, 2000)) > 0)
|
||
{
|
||
output.Write(buffer, 0, len);
|
||
}
|
||
output.Flush();
|
||
}
|
||
|
||
private string HMACSHA256(string identifier, long currTime, int expire, string base64UserBuf, bool userBufEnabled)
|
||
{
|
||
string rawContentToBeSigned = "TLS.identifier:" + identifier + "\n"
|
||
+ "TLS.sdkappid:" + sdkappid + "\n"
|
||
+ "TLS.time:" + currTime + "\n"
|
||
+ "TLS.expire:" + expire + "\n";
|
||
if (true == userBufEnabled)
|
||
{
|
||
rawContentToBeSigned += "TLS.userbuf:" + base64UserBuf + "\n";
|
||
}
|
||
using (HMACSHA256 hmac = new HMACSHA256())
|
||
{
|
||
UTF8Encoding encoding = new UTF8Encoding();
|
||
Byte[] textBytes = encoding.GetBytes(rawContentToBeSigned);
|
||
Byte[] keyBytes = encoding.GetBytes(key);
|
||
Byte[] hashBytes;
|
||
using (HMACSHA256 hash = new HMACSHA256(keyBytes))
|
||
hashBytes = hash.ComputeHash(textBytes);
|
||
return Convert.ToBase64String(hashBytes);
|
||
}
|
||
}
|
||
}
|
||
}
|