# 前言

本文档是蔚可云IM服务（IM）的开发帮助指南，描述了IM中的基本概念、提供的服务以及可用的API。

## 1.蔚可云IM服务简介

## 2.基本概念

## 3.IM功能简介

## 4.访问控制

### 4.1 签名认证(Authentication)

IM通过使用App Key / App Key Secret对称加密的方法来验证某个请求的发送者身份。App Key用于标示用户，App Key Secret是 用户用于加密签名字符串和IM用来验证签名字符串的密钥，其中App Key
Secret必须保密，只有用户和IM知道。每个ACCESS Key对（App Key 和App Key Secret）都有active/inactive两种状态。

- active表明用户可以用此ID对签名验证请求

- inactive表明用户暂停此ID对签名验证的功能

一个用户可以同时拥有0至1个active或者inactive的ID对。用户可以登录xxxxxxxx，在IM管理控制台申请新增或删除ID对。

当用户想以客户端身份向OSS发送请求时，需要首先将发送的请求按照IM指定的格式生成签名字符串；然后使用App Key Secret对签名字符串进行加密产生 验证码。 IM收到请求以后，会通过Access Key ID找到对应的App Key
Secret，以同样的方法提取签名字符串和验证码，如果计算出来的验证码和提供 的一样即认为该请求是有效的；否则，IM将拒绝处理这次请求，并返回HTTP 403错误。

### 4.2 在Head中包含签名

用户可以在HTTP请求中增加Authorization（授权）的Head来包含签名(Signature)信息，表明这个消息已被授权。

**Authorization字段计算方法如下**：

```
Authorization: OSS " + Access Key ID + ":" + Signature

Signature = base64(hmac-sha1(VERB + "\n"
                    + CONTENT-MD5 + "\n"
                    + CONTENT-TYPE + "\n"
                    + DATE + "\n"
                    + CanonicalizedOSSHeaders
                    + CanonicalizedResource))
```

- CONTENT-MD5表示请求内容数据的MD5值
- CONTENT-TYPE表示请求内容的类型
- DATE表示此次操作的时间，且必须为HTTP1.1中支持的GMT格式
- CanonicalizedOSSHeaders表示 http中的object meta组合
- CanonicalizedResource 表示用户想要访问的OSS资源

其中，DATE和CanonicalizedResource不能为空；如果请求中的DATE时间和OSS服务器的时间差正负15分钟以上，OSS服务器将拒绝该服务，并返回HTTP 403错误。

**构建CanonicalizedOSSHeaders的方法**： 所有以“x-oss-”为前缀的HTTP Header被称为CanonicalizedOSSHeaders。它的构建方法如下：

```
1)         将所有以“x-oss-”为前缀的HTTP请求头的名字转换成小写字母。如’X-OSS-Meta-Name: TaoBao’转换成’x-oss-meta-name: TaoBao’。
2)         将上一步得到的所有HTTP请求头按照字典序进行升序排列。
3)         如果有相同名字的请求头，则根据标准RFC 2616, 4.2章进行合并（两个值之间只用逗号分隔）。如有两个名为’x-oss-meta-name’的请求头，对应的值分别为’TaoBao’和’Alipay’，则合并后为：’x-oss-meta-name:TaoBao,Alipay’。
4)         删除请求头和内容之间分隔符两端出现的任何空格。如’x-oss-meta-name: TaoBao,Alipay’转换成：’x-oss-meta-name:TaoBao,Alipay’。
5)         将所有的头和内容用’\n’分隔符分隔拼成最后的CanonicalizedOSSHeader。
```

**构建CanonicalizedResource的方法**： 用户发送请求中想访问的OSS目标资源被称为CanonicalizedResource。它的构建方法如下：

```
1)         将CanonicalizedResource置成空字符串（“”）；
2)         放入要访问的OSS资源：“ /BucketName/ObjectName”（无ObjectName则不填）
3)         如果请求的资源包括子资源(sub-resource)[3]，那么将所有的子资源按照字典序，从小到大排列并以’&’为分隔符生成子资源字符串。在CanonicalizedResource字符串尾添加“？”和子资源字符串。此时的CanonicalizedResource例子如：/BucketName/ObjectName?acl &uploadId=UploadId
4)         如果用户请求在查询字符串(query string)中指定了要重写(override)返回请求的header[4]，那么将这些查询字符串及其请求值按照字典序，从小到大排列，以’&’为分隔符，按参数的字典序添加到CanonicalizedResource中。此时的CanonicalizedResource例子：
/BucketName/ObjectName?acl&response-content-type=ContentType & uploadId =UploadId
```

**例如：想签名以下信息：**

```
PUT /nelson HTTP/1.0
Content-Md5: c8fdb181845a4ca6b8fec737b3581d76
Content-Type: text/html
Date: Thu, 17 Nov 2005 18:49:58 GMT
Host: oss-example.oss.aliyuncs.com
X-OSS-Meta-Author: foo@bar.com
X-OSS-Magic: abracadabra
```

假如Access Key ID是： "44CF9590006BF252F707"
Access Key Secret是 "OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV"，可用以下方法签名(Signature):

**python示例代码**：

```
import base64
import hmac
import sha
h = hmac.new("OtxrzxIsfpFjA7SwPzILwy8Bw21TLhquhboDYROV",
             "PUT\nc8fdb181845a4ca6b8fec737b3581d76\ntext/html\nThu, 17 Nov 2005 18:49:58 GMT\nx-oss-magic:abracadabra\nx-oss-meta-author:foo@bar.com\n/oss-example/nelson", sha)
base64.encodestring(h.digest()).strip()
```

签名(Signature)计算结果应该为”63mwfl+zYIOG6k95yxbgMruQ6QI=”， 然后加上Authorization头来组成最后需要发送的消息：

```
PUT /nelson HTTP/1.0
Authorization: OSS 44CF9590006BF252F707: 63mwfl+zYIOG6k95yxbgMruQ6QI=
Content-Md5: c8fdb181845a4ca6b8fec737b3581d76
Content-Type: text/html
Date: Thu, 17 Nov 2005 18:49:58 GMT
Host: oss-example.oss.aliyuncs.com
X-OSS-Meta-Author: foo@bar.com
X-OSS-Magic: abracadabra
```

在计算签名头的时候请遵循如下规则：

1) 用来签名的字符串必须为UTF-8格式。含有中文字符的签名字符串必须先进行UTF-8编码，再与Access Key Secret计算最终签名。

2) 签名的方法用RFC 2104 (http://www.ietf.org/rfc/rfc2104.txt)中定义的HMAC-SHA1方法，其中Key为Access Key Secret。

3) content-type和content-md5在请求中不是必须的，但是如果请求需要签名验证，空值的话以换行符“\n”代替。

4) 在所有非HTTP标准定义的header中，只有以“x-oss-”开头的header，需要加入签名字符串；其他非HTTP标准header将被OSS忽略（如上例中的x-oss-magic）。

5) 以“x-oss-”开头的head在签名验证前需要符合以下规范：
   - head的名字需要变成小写。
   - head按字典序自小到大排序。
   - 分割head name和value的冒号前后不能有空格。
   - 每个Head之后都有一个换行符“\n”，如果没有Head，CanonicalizedOSSHeaders就设置为空。

**细节分析：**

如果传入的Access Key ID不存在或inactive，返回403 Forbidden。错误码：InvalidAccessKeyId。

2) 若用户请求头中Authorization值的格式不对，返回400 Bad Request。错误码：InvalidArgument。

3) OSS所有的请求都必须使用HTTP 1.1协议规定的GMT时间格式。其中，日期的格式有三种：

date1 = 2DIGIT SP month SP 4DIGIT; day month year (e.g., 02 Jun 1982)

date2 = 2DIGIT "-" month "-" 2DIGIT; day-month-year (e.g., 02-Jun-82)

date3 = month SP ( 2DIGIT | ( SP 1DIGIT )); month day (e.g., Jun 2)  【注意“2”前面有两个空格】

上述这三种日期格式中，“天”所占位数都是“2 DIGIT”。因此，“Jun 2”、“2 Jun 1982”和“2-Jun-82”都是非法日期格式。

4) 如果签名验证的时候，头中没有传入Date或者格式不正确，返回403 Forbidden错误。错误码：AccessDenied。

5) 传入请求的时间必须在OSS服务器当前时间之后的15分钟以内，否则返回403 Forbidden。错误码：RequestTimeTooSkewed。

6) 如果Access Key ID是active的，但OSS判断用户的请求发生签名错误，则返回403
   Forbidden，并在返回给用户的response中告诉用户正确的用于验证加密的签名字符串。用户可以根据OSS的response来检查自己的签名字符串是否正确。

**返回示例：**

```
<?xml version="1.0" encoding="UTF-8"?>
<Error xmlns=”http://doc.oss.aliyuncs.com”>
<Code>
           SignatureDoesNotMatch
</Code>
<Message>
          The request signature we calculated does not match the signature you provided. Check your key and signing method.
</Message>
<StringToSignBytes>
           47 45 54 0a 0a 0a 57 65 64 2c 20 31 31 20 4d 61 79 20 32 30 31 31 20 30 37 3a 35 39 3a 32 35 20 47 4d 54 0a 2f 75 73 72 65 61 6c 74 65 73 74 3f 61 63 6c
</StringToSignBytes>
<RequestId>
           1E446260FF9B10C2
</RequestId>

<HostId>
           oss.aliyuncs.com
</HostId>

<SignatureProvided>
           y5H7yzPsA/tP4+0tH1HHvPEwUv8=
</SignatureProvided>

<StringToSign>
           GET
Wed, 11 May 2011 07:59:25 GMT
/oss-example?acl
</StringToSign>

<OSSAccessKeyId>
           AKIAIVAKMSMOY7VOMRWQ
</OSSAccessKeyId>

</Error>
```

## 5.开放接口规范

## 6.错误响应
