C# 生成腾讯云 IM 之 TLSSigAPIv2 UserSig

2024-06-20 13:29:11 浏览数 (2)

关于腾讯 IM 开发

腾讯微信已经成为当今绝大多数用户必不可少的聊天和通讯工具,腾讯也是国内最早也是最大的即时通信开发商 。腾讯云将高并发、高可靠的即时通信能力以 SDK 和 REST API的形式进行开放,推出即时通信 IM 产品,可以通过简易的方式将腾讯云提供的 IM SDK 集成进自有应用中,配合服务端 REST API 调用,即可轻松拥有微信一样强大的即时通信能力。

关于 UserSig

UserSig 是用户登录即时通信 IM 的密码,其本质是对 UserID 等信息加密后得到的密文,采用服务端计算 UserSig,可以最大限度地保障计算 UserSig 所用的密钥信息不被泄露。本文将介绍如何使用 C# 通过 TLSSigAPIv2 类计算 UserSig 的方法。

范例运行环境

操作系统: Windows Server 2019 DataCenter

.net版本: .netFramework4.0 或以上

开发工具:VS2019 C#

TLSSigAPIv2 类

设计

TLSSigAPIv2 类提供了一系列方法,用于生成UserSig,其关键属性方法说明如下:

序号

类型

说明

1

private readonly int sdkappid

属性

sdk开发者id,如何获取请参照如下链接: 腾讯IM即时通信控制台

2

private readonly string key

属性

sdk开发者key ,如何获取请参照如下链接: 腾讯IM即时通信控制台

3

private string HMACSHA256(string identifier, long currTime, int expire, string base64UserBuf, bool userBufEnabled)

方法

HMAC-SHA256 算法方法。即时通信 IM 服务自2019.07.19开始启用新的签名算法,从之前的 ECDSA-SHA256 升级为 HMAC-SHA256。 2019.07.19以后创建的 SDKAppID 均会采用新的 HMAC-SHA256 算法。

4

public string GenSig(string identifier, int expire = 180 * 86400)

方法

生成UserSig方法。 参数:Identifier为用户 ID; 参数:expire为有效期,单位为秒。建议 UserSig 有效期最短不小于24小时,最长不超过50年。为了您的账号安全,建议将 UserSig 有效期设置为两个月。

实现

实现代码如下:

代码语言:javascript复制
public class TLSSigAPIv2
{
             private readonly int sdkappid;
             private readonly string key;

             public TLSSigAPIv2(int sdkappid, string key)
             {
                 this.sdkappid = sdkappid;
                 this.key = key;
             }

             public byte[] GetUserBuf(string account, uint authId, uint expireTime, uint privilegeBitMap, uint accountType)
             {
                 int length = 1   2   account.Length   20;
                 int offset = 0;
                 byte[] userBuf = new byte[length];

                 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;

                 userBuf[offset  ] = (byte)((sdkappid & 0xFF000000) >> 24);
                 userBuf[offset  ] = (byte)((sdkappid & 0x00FF0000) >> 16);
                 userBuf[offset  ] = (byte)((sdkappid & 0x0000FF00) >> 8);
                 userBuf[offset  ] = (byte)(sdkappid & 0x000000FF);

                 userBuf[offset  ] = (byte)((authId & 0xFF000000) >> 24);
                 userBuf[offset  ] = (byte)((authId & 0x00FF0000) >> 16);
                 userBuf[offset  ] = (byte)((authId & 0x0000FF00) >> 8);
                 userBuf[offset  ] = (byte)(authId & 0x000000FF);

                 userBuf[offset  ] = (byte)((expireTime & 0xFF000000) >> 24);
                 userBuf[offset  ] = (byte)((expireTime & 0x00FF0000) >> 16);
                 userBuf[offset  ] = (byte)((expireTime & 0x0000FF00) >> 8);
                 userBuf[offset  ] = (byte)(expireTime & 0x000000FF);

                 userBuf[offset  ] = (byte)((privilegeBitMap & 0xFF000000) >> 24);
                 userBuf[offset  ] = (byte)((privilegeBitMap & 0x00FF0000) >> 16);
                 userBuf[offset  ] = (byte)((privilegeBitMap & 0x0000FF00) >> 8);
                 userBuf[offset  ] = (byte)(privilegeBitMap & 0x000000FF);

                 userBuf[offset  ] = (byte)((accountType & 0xFF000000) >> 24);
                 userBuf[offset  ] = (byte)((accountType & 0x00FF0000) >> 16);
                 userBuf[offset  ] = (byte)((accountType & 0x0000FF00) >> 8);
                 userBuf[offset  ] = (byte)(accountType & 0x000000FF);

                 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);
                 }
             }

             private string GenSig(string identifier, 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(identifier, currTime, expire, base64UserBuf, userBufEnabled);
                     // 没有引入 json 库,所以这里手动进行组装,
                     // 这里如果用户 identifier 中出现 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}""
                          "}}", identifier, sdkappid, expire, currTime, base64sig, base64UserBuf);
                 }
                 else
                 {
                     // 没有引入 json 库,所以这里手动进行组装
                     string base64sig = HMACSHA256(identifier, 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}""
                           "}}", identifier, sdkappid, expire, currTime, base64sig);
                 }

                 byte[] buffer = Encoding.UTF8.GetBytes(jsonData);
                 return Convert.ToBase64String(CompressBytes(buffer))
                     .Replace(' ', '*').Replace('/', '-').Replace('=', '_');
             }

             public string GenSig(string identifier, int expire = 180 * 86400)
             {
                 return GenSig(identifier, expire, null, false);
             }

             public string GenSigWithUserBuf(string identifier, int expire, byte[] userBuf)
             {
                 return GenSig(identifier, expire, userBuf, true);
             }
}

小结

服务端的调用引用代码如下:

代码语言:javascript复制
string SDKAppId="申请的SDKAppID";  
string SDKAppIdSecret="申请的SDKAppIdSecret";  
string AppAdminId="IM平台超级管理员UserID";

TLSSigAPIv2 sig = new TLSSigAPIv2(int.Parse(SDKAppId),SDKAppIdSecret);
string _sig = sig.GenSig(AppAdminId);

后续我们将介绍如何通过UserSig 来实现 IM 服务端 REST API,REST API 是即时通信 IM 提供给 App 后台的 HTTP 管理接口,是一组原始的且管理功能强大的API。

本文代码仅供您参考使用,感谢您的阅读,希望本文能够对您有所帮助。

0 人点赞