本文介绍AIMPaaS回调服务的架构、回调参数、回调列表和签名算法。

简介

AIMPaaS提供了强大的回调能力,让业务方能够在某个调用之前向AppServer发送请求,AppServer可根据回调语义干预后续处理流程。

默认只有AppClient通过IMSDK发起的请求才会有回调,AppServer直接调用AIMPaaS不会发起回调。目前支持的回调请参见回调列表

架构

AIMPaaS的回调服务使用流程如下。

IM回调架构
  1. 业务侧,开发者预先使用控制台登记用于接收回调请求的HTTP URL。
  2. 设置回调URL后,平台会颁发一个用于回调的AppKey和AppSecret。
  3. 平台通过HTTP/HTTPS方式将回调请求发送给AppServer(业务服务端)。
  4. AppServer收到请求后应先校验请求合法性,并尽快进行应答。

注册回调

  1. 业务方预先在控制台上登记用于接收回调请求的HTTP URL,平台会颁发一个用于回调的AppKey和AppSecret。
  2. 平台通过HTTP/HTTPS方式将回调请求发送给AppServer,AppServer收到请求后应先校验请求合法性,并尽快进行应答。

回调参数

请求参数
  • Header
    • method:POST
    • content-type:application/x-www-form-urlencoded
  • Body
    单表解析后如下所示:
    名称 类型 是否必选 示例值 描述
    command String Callback.CreateGroup 回调类型,取值见回调列表。
    data String {"creatorAppUid": "12345", "initMembers": []} 回调请求内容,具体见每个回调的请求参数。
    ispSignature String 876yvrIsoGSox35bolbXPrs7Gvc=" 加签后的值,开发者通过签名校验,HTTP请求的合法性。
    ispSignatureSecretKey String signkeyname 验证签名的Key,开发者需要维护Key对应的密钥。
返回参数
  • Header

    content-type:JSON

  • Body
    单表解析后如下所示:
    名称 类型 是否必选 示例值 描述
    data String "result": { "allow": true, "code": "0xx", "reason": "security " } 回调应答内容,具体见每个回调的应答参数。

回调列表

名称 Command 描述
消息发送回调 Callback.SendMessage 客户端发送的消息,在消息处理之前,会回调业务服务端,业务方可判断消息是否可以发送。
群聊创建回调 Callback.CreateGroup 客户端发起的群聊会话创建,AIMPaaS会回调业务服务端,业务方可校验群是否可创建。
群成员添加回调 Callback.AddGroupMember 客户端发起的群聊会话加人,AIMPaaS会回调业务服务端,业务方可校验加人操作是否允许。
群成员删除回调 Callback.RemoveGroupMember 客户端发起的群聊会话踢人,AIMPaaS会回调业务服务端,业务方校验踢人操作是否允许。
单聊会话创建回调 Callback.CreateSingleChat 客户端发起的单聊会话创建,AIMPaaS会回调业务服务端,会话ID可在回调中生成。AIMPaaS中会话是由会话ID唯一标识。
说明 如果开发者选用了标准单聊,不需要实现该回调。
单聊会话视图创建回调 Callback.AddUserConversation 用户添加单聊会话时,使用该回调业务服务端获取会话视图信息。
说明 如果开发者选用了标准单聊,不需要实现该回调。

签名算法


/**
  BodyToSign
    1. 解析HTTP BODY:argsMap = parseForm
    2. 对Form的参数key按照字典序升序排列,sortedArgs
    3. 遍历sortedArgs:"&" + key + "=" + percentEncode("/")
 */
StringToSign = HTTP-Method + "&" + percentEncode("/") + bodyToSign;

Signature = Base64Encode(hmacSha1(AccessSecret + "&" + stringToSign));

/**
    1. 读取Request中除"IspSignature"参数外的所有参数。
    2. 按照参数名称的字典顺序对参数进行排序。
    3. 对每个请求参数的名称和值进行编码。名称和值要使用UTF-8 字符集进行URL编码,URL编码的编码规则是:
        a. 对于字符 A-Z、a-z、0-9 以及字符“-”、“_”、“.”、“~”不编码;
        b. 对于其他字符编码成 “%XY” 的格式,其中 XY 是字符对应 ASCII 码的 16 进制表示。比如英文的双引号 (”)对应的编码就是 %22
    4. 对于扩展的 UTF-8 字符,编码成 “%XY%ZA...” 的格式。
    5. 需要说明的是英文空格( )要被编码是 %20,而不是加号(+)。
    
    注:一般支持 URL 编码的库(比如 Java 中的 java.net.URLEncoder)都是按照 “application/x- www-form-urlencoded” 的 MIME 类型的规则进行编码的。实现时可以直接使用这类方式进行编 码,把编码后的字符串中加号(+)替换成 %20、星号(*)替换成 %2A、%7E 替换回波浪号 (~),即可得到上述规则描述的编码字符串。
    1. 对编码后的参数名称和值使用英文等号(=)进行连接。
    2. 再把英文等号连接得到的字符串按参数名称的字典顺序依次使用&符号连接,即得到规范化请求字符串。
  */
Java版签名实现Demo
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.xml.crypto.dsig.SignatureMethod;
import org.apache.commons.codec.binary.Base64;


  /**
     * RPC签名
     *
     * @return
     * @throws UnsupportedEncodingException
     */
    private String rpcSign(HttpServletRequest request)
            throws Exception {
        List<String> keys = new ArrayList<String>(request.getParameterMap().keySet());
        Collections.sort(keys);
        StringBuilder sb = new StringBuilder();
        for (String key : keys) {
            if (key.equals("IspSignature")){
                continue;
            }

            String value = request.getParameter(key);
            sb.append("&").append(percentEncode(key)).append("=").append(percentEncode(value));
        }

        StringBuilder stringToSign = new StringBuilder();
        stringToSign.append(percentEncode(request.getMethod()));
        stringToSign.append("&");
        stringToSign.append(percentEncode("/"));
        stringToSign.append("&");
        stringToSign.append(percentEncode(sb.substring(1)));

        SecretKey key = new SecretKeySpec(("YourSecretKey" + "&").getBytes("utf-8"), SignatureMethod.HMAC_SHA1);
        Mac hmacSha1 = Mac.getInstance("HmacSHA1");
        hmacSha1.init(key);

        String sign = new String(new Base64().encode(hmacSha1.doFinal(stringToSign.toString().getBytes("utf-8"))),
                        "utf-8");

        return sign;
    }

 /**
    * 处理特殊字符
    *
    * @param s
    * @return
    * @throws UnsupportedEncodingException
    */
   protected String percentEncode(String s) throws UnsupportedEncodingException {
       if (s == null){
           return null;
       }
       return URLEncoder.encode(s, "utf-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~");
   }