前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >云通信IM登录鉴权解密

云通信IM登录鉴权解密

原创
作者头像
linpeiyang@云通信专项团队
修改2020-11-24 10:41:44
3.8K0
修改2020-11-24 10:41:44
举报

概念

云通信IM的前身是QQ,我们抽离QQ的核心模块,将其整合成适合各终端接入的 IM SDK以及后台服务。

如同QQ一样,云通信IM的核心功能是用来收发消息,但前提是用户必须先登录才能使用。登录QQ用的是QQ号和密码,登录云通信IM则是用用户名 UserID密码 UserSig

UserID: 也称为identifier, 用户登录云通信IM时使用的用户名

UserSig: 用户登录云通信IM时使用的密码,本质上是将UserID等信息加密过后得到的密文

登录鉴权流程

这里有三种角色:

云通信IM后台:腾讯云云通信IM的服务端后台

开发者后台:开发者的服务端后台

开发者应用:开发者使用IMSDK开发的给用户使用的终端

登录三步:

登录流程
登录流程

1. 用户的APP带上UserID请求开发者后台,请求UserSig

2. 开发者后台使用云通信IM的UserSig生成库,生成UserSig并返回给应用

3. 应用使用UserID和UserSig访问云通信IM后台进行登录

(登录成功后,UserSig会储存在开发者应用的内存里)

鉴权:

通过登录三步,成功登录后,应用将收到云通信IM返回的此用户在云通信IM应用登录成功的凭证(我们称为票据),凭证会存储在开发者应用本地,之后使用云通信IM的提供的核心功能时,云通信IM后台将根据凭证进行鉴权。

如何生成UserSig

有两种方式:

1. 开发者应用本地生成

2. 开发者后台生成

其中,不推荐开发者应用本地生成的方式,原因是客户端代码容易被反编译导致密钥泄露,攻击者将可以使用密钥生成UserSig,成功登录盗用开发者的腾讯云流量。

因此推荐使用开发者后台生成UserSig, 服务器的攻击成本更高,用此种方式将能更好保护开发者的密钥。

开发者后台生成

在开发者后台,实际上调用云通信IM生成UserSig的库,把以下三个重要信息进行对称加密(非对称的方式已经停用),生成UserSig

SdkAppid:云通信IM应用的唯一ID

SecretKey:云通信IM应用的唯一密钥

ExpireTime:密码过期时间,开发者指定

算法实现源码: JAVA - https://github.com/tencentyun/tls-sig-api-v2-java/blob/master/src/main/java/com/tencentyun/TLSSigAPIv2.java

GO - https://github.com/tencentyun/tls-sig-api-v2-golang/blob/master/tencentyun/TLSSigAPI.go

PHP - https://github.com/tencentyun/tls-sig-api-v2-php/blob/master/src/TLSSigAPIv2.php

Nodejs - https://github.com/tencentyun/tls-sig-api-v2-node/blob/master/TLSSigAPIv2.js

Python - https://github.com/tencentyun/tls-sig-api-v2-python/blob/master/TLSSigAPIv2.py

C# - https://github.com/tencentyun/tls-sig-api-v2-cs/blob/master/tls-sig-api-v2-cs/TLSSigAPIv2.cs

C++ - https://github.com/tencentyun/tls-sig-api-v2-cpp

java源码片段:

GenTLSSignature方法:将信息摘要,使用hmacsha256方法生成UserSig,压缩

hmacsha256方法:调用标准库里的hmac方法进行加密

代码语言:javascript
复制
    private static String GenTLSSignature(long sdkappid, String userId, long expire, byte[] userbuf, String priKeyContent) {
        if (TextUtils.isEmpty(priKeyContent)) {
            return "";
        }
        long currTime = System.currentTimeMillis() / 1000;
        JSONObject sigDoc = new JSONObject();
        try {
            sigDoc.put("TLS.ver", "2.0");
            sigDoc.put("TLS.identifier", userId);
            sigDoc.put("TLS.sdkappid", sdkappid);
            sigDoc.put("TLS.expire", expire);
            sigDoc.put("TLS.time", currTime);
        } catch (JSONException e) {
            e.printStackTrace();
        }

        String base64UserBuf = null;
        if (null != userbuf) {
            base64UserBuf = Base64.encodeToString(userbuf, Base64.NO_WRAP);
            try {
                sigDoc.put("TLS.userbuf", base64UserBuf);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
        String sig = hmacsha256(sdkappid, userId, currTime, expire, priKeyContent, base64UserBuf);
        if (sig.length() == 0) {
            return "";
        }
        try {
            sigDoc.put("TLS.sig", sig);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        Deflater compressor = new Deflater();
        compressor.setInput(sigDoc.toString().getBytes(Charset.forName("UTF-8")));
        compressor.finish();
        byte[] compressedBytes = new byte[2048];
        int compressedBytesLength = compressor.deflate(compressedBytes);
        compressor.end();
        return new String(base64EncodeUrl(Arrays.copyOfRange(compressedBytes, 0, compressedBytesLength)));
    }
        
        
    private static String hmacsha256(long sdkappid, String userId, long currTime, long expire, String priKeyContent, String base64Userbuf) {
        String contentToBeSigned = "TLS.identifier:" + userId + "\n"
                + "TLS.sdkappid:" + sdkappid + "\n"
                + "TLS.time:" + currTime + "\n"
                + "TLS.expire:" + expire + "\n";
        if (null != base64Userbuf) {
            contentToBeSigned += "TLS.userbuf:" + base64Userbuf + "\n";
        }
        try {
            byte[] byteKey = priKeyContent.getBytes("UTF-8");
            Mac hmac = Mac.getInstance("HmacSHA256");
            SecretKeySpec keySpec = new SecretKeySpec(byteKey, "HmacSHA256");
            hmac.init(keySpec);
            byte[] byteSig = hmac.doFinal(contentToBeSigned.getBytes("UTF-8"));
            return new String(Base64.encode(byteSig, Base64.NO_WRAP));
        } catch (UnsupportedEncodingException e) {
            return "";
        } catch (NoSuchAlgorithmException e) {
            return "";
        } catch (InvalidKeyException e) {
            return "";
        }
    }

引入上述的库后,开发者后台调用TLSSigAPIv2的类方法genSig生成UserSig,java代码举例:

代码语言:javascript
复制
public class UserSigSerivce {
    private long sdkAppid;
    private String secretKey;
    private long expire = 60*60*27*7; //开发者自定过期时间,比如7天

    public String generateUserSig(String userid){
        TLSSigAPIv2 api = new TLSSigApiv2(sdkAppid, secretKey);
        return api.genSig(userid, expire)
    }
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
作者已关闭评论
0 条评论
热度
最新
推荐阅读
目录
  • 概念
  • 登录鉴权流程
    • 登录三步:
      • 鉴权:
      • 如何生成UserSig
        • 开发者后台生成
        相关产品与服务
        SSL 证书
        腾讯云 SSL 证书(SSL Certificates)为您提供 SSL 证书的申请、管理、部署等服务,为您提供一站式 HTTPS 解决方案。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档