美文网首页
Springboot 技术整合--笔记17-tencentIM

Springboot 技术整合--笔记17-tencentIM

作者: 牵手生活 | 来源:发表于2020-05-03 17:51 被阅读0次

    本文内容


    参考资料

    Java后台服务端接入腾讯IM
    tencentIM官方文档

    usesrsig(token)算法参考官方文档

    UserSig 是用户登录即时通信 IM 的密码,其本质是对 UserID 等信息加密后得到的密文,本文将指导您如何生成 UserSig
    UserSig一般采用web后台提供api方式,增加安全性。
    UserSig很多web后台,把其成为token
    比如在Android app项目中登录的信息如下

    userSig =eJwtjNEKgjAUQP-lPofcuWkq9CgaGgUGRW-m1ritZKiELPr3RH0858D5wrmsvI-qIAHfQ9jMTFK1Az1o1k3jnNaMra2XpraWJCRMIHIeCuYvRY2WOgVJiCJCXNxA78mwIIpEHDN-uz5IT2Mj9q3RB*TdrRhzeerTMrsET*SGO7zzwuWyOr6yq637Hfz*ZxQx1w__
    
    image.png
    usersig官方生成demo(android方提供转Java)
    package cn.stylefeng.guns.core.util;
    
    
    
    import com.alibaba.fastjson.JSONException;
    import com.alibaba.fastjson.JSONObject;
    import com.qiniu.util.Base64;
    import org.apache.commons.lang.StringUtils;
    
    import java.io.UnsupportedEncodingException;
    import java.nio.charset.Charset;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    import java.util.Arrays;
    import java.util.zip.Deflater;
    
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    
    /*
     * Module:   GenerateTestUserSig
     *
     * Function: 用于生成测试用的 UserSig,UserSig 是腾讯云为其云服务设计的一种安全保护签名。
     *           其计算方法是对 SDKAppID、UserID 和 EXPIRETIME 进行加密,加密算法为 HMAC-SHA256。
     *
     * Attention: 请不要将如下代码发布到您的线上正式版本的 App 中,原因如下:
     *
     *            本文件中的代码虽然能够正确计算出 UserSig,但仅适合快速调通 SDK 的基本功能,不适合线上产品,
     *            这是因为客户端代码中的 SECRETKEY 很容易被反编译逆向破解,尤其是 Web 端的代码被破解的难度几乎为零。
     *            一旦您的密钥泄露,攻击者就可以计算出正确的 UserSig 来盗用您的腾讯云流量。
     *
     *            正确的做法是将 UserSig 的计算代码和加密密钥放在您的业务服务器上,然后由 App 按需向您的服务器获取实时算出的 UserSig。
     *            由于破解服务器的成本要高于破解客户端 App,所以服务器计算的方案能够更好地保护您的加密密钥。
     *
     * Reference:https://cloud.tencent.com/document/product/269/32688#Server
     */
    public class TencentIMGenerateTestUserSig {
    
        /**
         * 腾讯云 SDKAppId,需要替换为您自己账号下的 SDKAppId。
         *
         * 进入腾讯云云通信[控制台](https://console.cloud.tencent.com/avc ) 创建应用,即可看到 SDKAppId,
         * 它是腾讯云用于区分客户的唯一标识。
         */
        public static final int SDKAPPID = *****在tencentIM控制台中查看;
    
    
        /**
         * 签名过期时间,建议不要设置的过短
         * <p>
         * 时间单位:秒
         * 默认时间:7 x 24 x 60 x 60 = 604800 = 7 天
         */
        private static final int EXPIRETIME = 604800;
    
    
        /**
         * 计算签名用的加密密钥,获取步骤如下:
         *
         * step1. 进入腾讯云云通信[控制台](https://console.cloud.tencent.com/avc ) ,如果还没有应用就创建一个,
         * step2. 单击“应用配置”进入基础配置页面,并进一步找到“帐号体系集成”部分。
         * step3. 点击“查看密钥”按钮,就可以看到计算 UserSig 使用的加密的密钥了,请将其拷贝并复制到如下的变量中
         *
         * 注意:该方案仅适用于调试Demo,正式上线前请将 UserSig 计算代码和密钥迁移到您的后台服务器上,以避免加密密钥泄露导致的流量盗用。
         * 文档:https://cloud.tencent.com/document/product/269/32688#Server
         */
        private static final String SECRETKEY = "*****在tencentIM控制台中查看";
    
        /**
         * 计算 UserSig 签名
         *
         * 函数内部使用 HMAC-SHA256 非对称加密算法,对 SDKAPPID、userId 和 EXPIRETIME 进行加密。
         *
         * @note: 请不要将如下代码发布到您的线上正式版本的 App 中,原因如下:
         *
         * 本文件中的代码虽然能够正确计算出 UserSig,但仅适合快速调通 SDK 的基本功能,不适合线上产品,
         * 这是因为客户端代码中的 SECRETKEY 很容易被反编译逆向破解,尤其是 Web 端的代码被破解的难度几乎为零。
         * 一旦您的密钥泄露,攻击者就可以计算出正确的 UserSig 来盗用您的腾讯云流量。
         *
         * 正确的做法是将 UserSig 的计算代码和加密密钥放在您的业务服务器上,然后由 App 按需向您的服务器获取实时算出的 UserSig。
         * 由于破解服务器的成本要高于破解客户端 App,所以服务器计算的方案能够更好地保护您的加密密钥。
         *
         * 文档:https://cloud.tencent.com/document/product/269/32688#Server
         */
        public static String genTestUserSig(String userId) {
            return GenTLSSignature(SDKAPPID, userId, EXPIRETIME, null, SECRETKEY);
        }
    
        /**
         * 生成 tls 票据
         *
         * @param sdkappid    应用的 appid
         * @param userId      用户 id
         * @param expire      有效期,单位是秒
         * @param userbuf     默认填写null
         * @param priKeyContent 生成 tls 票据使用的私钥内容
         * @return 如果出错,会返回为空,或者有异常打印,成功返回有效的票据
         */
        private static String GenTLSSignature(long sdkappid, String userId, long expire, byte[] userbuf, String priKeyContent) {
            if (StringUtils.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);  //使用千牛用库正好有该参数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 "";
            }
        }
    
        private static byte[] base64EncodeUrl(byte[] input) {
            byte[] base64 = new String(Base64.encode(input, Base64.NO_WRAP)).getBytes();
            for (int i = 0; i < base64.length; ++i)
                switch (base64[i]) {
                    case '+':
                        base64[i] = '*';
                        break;
                    case '/':
                        base64[i] = '-';
                        break;
                    case '=':
                        base64[i] = '_';
                        break;
                    default:
                        break;
                }
            return base64;
        }
    
    }
    
    

    controller 提供获取usesrsig(token)

                        //获取tencentIM的Token
                        Map<String, Object> map = new HashMap<>();
    
                        String mymUserAccount = deviceWxNumber;//"cczzgg11";
                        String tencentIM_userSig = TencentIMGenerateTestUserSig.genTestUserSig(mymUserAccount);
                        map.put("token",tencentIM_userSig);
    
                        return IJSONResult.ok(map);
    

    为tencentIM 定义TencentIMSendMessageBean(查阅官方文档)

    查阅官方文档
    消息格式描述

    编写controller

    
    /**
     * 参考:SpringBoot(post、get)中获取客户请求信息、消息头、参数;get请求设置参数,使用场景
     * https://blog.csdn.net/qq_41767337/article/details/89144733
     *xuan
     */
    
    @Api(tags = "TencentIM的相关参数调用")
    @Controller
    @RequestMapping("wechatTask")
    public class TencentIMClientController {
        Logger logger = LoggerFactory.getLogger(TencentIMClientController.class);
    
        @PostMapping("/api_hjzx/doTencentIMTest")
        @ResponseBody
        //@RequestBody  ==采用@RestController 不再需要这个
        public IJSONResult doTencentIMTest(
                @ApiParam(name="content",value="数据内容",required=true) @RequestBody String  content
        ){
    
            try {
    
                JSONObject jsonObject = JSON.parseObject(content);
                int wechat_id = jsonObject.getInteger("wechat_id");
                JSONObject jsonObjectTask = jsonObject.getJSONObject("task");
                //int task_task_type = jsonObjectTask.getInteger("task_type");  //null 发送消息;0:好友操作;1:发送朋友圈;99:获取朋友圈数据
    
                JSONObject jsonObjectTask_task_single_msg = jsonObjectTask.getJSONObject("task_single_msg"); //发送消息txt、img、video、voice、link
                JSONObject jsonObject_task_sns = jsonObjectTask.getJSONObject("task_sns"); //朋友圈数据
                JSONObject jsonObjectTask_task_friends = jsonObjectTask.getJSONObject("task_friends");
    
                if (jsonObjectTask_task_single_msg !=null){//发送消息
                    int task_type = jsonObjectTask_task_single_msg.getInteger("task_type");
    
                    String str_ImMsg = "这是发送的task文本内容";
                    switch (task_type){
                        case 0://txt
                            str_ImMsg = str_ImMsg+"==TXT";
                            break;
                        case 1: //图片
                            str_ImMsg = str_ImMsg+"==img";
                            break;
                        case 2: //voice
                            str_ImMsg = str_ImMsg+"==voice";
                            break;
                        case 3: //video
                            str_ImMsg = str_ImMsg+"==video";
                            break;
    
    
                    }
                    TencentIMSendMessageBean sendMessageBean = new TencentIMSendMessageBean();
                    sendMessageBean.setMsgLifeTime(600 * 10);
                    sendMessageBean.setSyncOtherMachine(2);
                    String account =null ;
                    if (wechat_id ==69){
                        account = "cczzgg";
    
                    }
                    sendMessageBean.setTo_Account(account);
                    int intFlag = (int) (Math.random() * 100000000);
                    sendMessageBean.setMsgRandom(intFlag);
                    sendMessageBean.setMsgTimeStamp((int) (new Date().getTime() / 1000));
                    TencentIMSendMessageBean.MsgBodyBean msgBodyBean = new TencentIMSendMessageBean.MsgBodyBean();
                    msgBodyBean.setMsgType("TIMTextElem");  //设置为txt
    
    
                    //设置消息类型 + 消息内容
                    TencentIMSendMessageBean.MsgBodyBean.MsgContentBean msgContentBean = new TencentIMSendMessageBean.MsgBodyBean.MsgContentBean();
                    msgContentBean.setText(str_ImMsg);
                    msgBodyBean.setMsgContent(msgContentBean);
    
    
    
                    //添加到消息的List中去
                    sendMessageBean.getMsgBody().add(msgBodyBean);
    
    
                    RestTemplate restTemplate = new RestTemplate();
                    //rpc调用
                    restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
                    String myAdministrator = "administrator";
                    String UserSig = TencentIMGenerateTestUserSig.genTestUserSig(myAdministrator);
    
                    String tencentResult = restTemplate.postForObject("https://console.tim.qq.com/v4/openim/sendmsg?usersig=" + UserSig + "&apn=1&identifier="+myAdministrator+"&sdkappid="
                            + TencentIMGenerateTestUserSig.SDKAPPID + "&contenttype=json", JSONObject.toJSONString(sendMessageBean), String.class);
    
                    //如果有测试号,则也发送一份给测试号
                    String testAccount = "cczzgg11";  //测试好
                    if(StringUtils.isNotEmpty(testAccount)&&!testAccount.equals(myAdministrator)){
                        sendMessageBean.setTo_Account(testAccount);
                        String tencentResult_forTestAccount =restTemplate.postForObject("https://console.tim.qq.com/v4/openim/sendmsg?usersig=" + UserSig + "&apn=1&identifier="+myAdministrator+"&sdkappid="
                                + TencentIMGenerateTestUserSig.SDKAPPID
                                + "&contenttype=json", JSONObject.toJSONString(sendMessageBean), String.class);
                        logger.error(tencentResult_forTestAccount);
                    }
                    logger.error(tencentResult);
    
    
    
    
                    return IJSONResult.ok("发送完成,其他逻辑正在编写代码中。。。。");
    
    
                }
    
                if (jsonObject_task_sns != null){
                    return IJSONResult.ok("正在编写代码中。。。。");
    
                }
                if (jsonObjectTask_task_friends != null){
                    return IJSONResult.ok("正在编写代码中。。。。");
    
                }
    
    
                //可以添加处理逻辑
            } catch (Exception e) {
                logger.error("doTencentIMTest  body 中的参数参数失败");
    
    
            }
            return  IJSONResult.errorMsg("还没支撑的任务类型");
    
    
    
    
    
        }
    
    
    }
    
    

    postman测试

    image.png

    tencentIM官方demo收到消息

    tencentIM官方demo收到消息

    tencentIM的回调方式处理--登录状态或发送消息监控

    相关文章

      网友评论

          本文标题:Springboot 技术整合--笔记17-tencentIM

          本文链接:https://www.haomeiwen.com/subject/zzzdghtx.html