
# 开发概述
#### 关于认证
在系统间API交互时，需要对API做认证。CraftArts IPDCenter定义了API认证的规范与SDK，应用在与CraftArts IPDCenter的API集成过程中，需要按照此规范完成认证逻辑。
#### 认证集成简介
CraftArts IPDCenter提供卡片市场功能，在卡片市场中，第三方应用可以上传自定义卡片，卡片会调用第三方应用的API，此时API需要检验请求的合法性，通过集成认证SDK，可实现API合法性校验。
#### 工作原理
统一认证SDK是基于JWT实现的一种认证机制，Json web token (JWT)是在网络应用环境间为了传递声明而执行的一种基于JSON的开放标准(RFC 7519)。该token的设计紧凑且安全，特别适用于分布式站点的单点登录（SSO）场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息，以便从资源服务器获取资源。它也可以被增加一些其它业务逻辑所必须的声明信息。该token可直接被用于认证，也可被加密。
API请求方将请求的用户信息利用私钥哈希生成签名，将用户信息与签名合并生成token，在调用API时将token传递给被调用方，API被调用方获取到此token后，利用公钥验证此token的正确性。
图1机机认证方案   
![](https://support.huaweicloud.com/devg-craftartsipdcenter/figure/zh-cn_image_0000001834445978.png "点击放大")
#### JWT的组成
图2Json web token   
![](https://support.huaweicloud.com/devg-craftartsipdcenter/figure/zh-cn_image_0000001798351065.png "点击放大")
一个JWT实际上就是一个字符串，它由三部分组成，头部、载荷与签名。形式为：
```
A.B.C
```
样本数据如下：
```
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJhdWQiOlsiZGVmYXVsdCIsImdhdGV3YXkiXSwiYXBwSWQiOiJkZWZhdWx0IiwiaXNzIjoiZGVmYXVsdCIsImV4cCI6MTU0NDY5MDY0NywiaWF0IjoxNTQ0Njg4ODQ3fQ.J-ngHZy8009k-OAQ7-6Jt2kUzsml6N60d-atVIP3UydsQH_GqFv4rSY_uliqZ2_8ecgcKm0pWAAFtN88t7ehVQ
```
**头部（ Header ）**
JWT需要一个头部，头部用于描述关于该JWT的最基本的信息，例如其类型以及签名所用的算法等。
头部信息是经过BASE64编码的，包括以下几个属性：
表1属性 
| 位置     | 字段  | 名称   | 是否必填 | 字段类型   | 字段说明                         |
|:---|:---|:---|:---|:---|:---|
| Header | typ | 类型   | 是    | String | 固定值：JWT                      |
| Header | alg | 算法   | 是    | String | 固定值：RSA                      |
| Header | kid | 密钥ID | 是    | String | 密钥ID，由CraftArts IPDCenter颁发。 |
   
**载荷（Payload）**
载荷信息是经过BASE64编码解码后的JSON对象，包括以下几个属性：
表2属性 
| 位置      | 字段     | 名称    | 是否必填 | 字段类型                  | 字段说明           | 使用方式                                                                                                                                                                                                                                                                                                                                                                                                             |
|:---|:---|:---|:---|:---|:---|:---|
| Payload | iss    | 发行人   | 否    | String                | 该JWT的签发者       | - 如果由机机自动触发，则放appId（appId可在IPDCenter基础服务"管理中心 \> 应用集成 \> 密钥管理"中获取）；  - 如果由人触发调用，可以放userName:userId:tenantId:teamId（用户名:用户Id:租户Id:用户所在团队Id，团队Id主要用于数据鉴权使用，不涉及时可不传）。   |
| Payload | sub    | 主题    | 否    | String                | 该JWT所面向的用户     | 暂时为空，建议为被调用方appId                                                                                                                                                                                                                                                                                                                                                                                                |
| Payload | aud    | 接收系统  | 否    | String\[\]            | 接收该JWT的一方      | 目标系统的{域名:端口/上下文根}                                                                                                                                                                                                                                                                                                                                                                                                |
| Payload | exp    | 过期时间  | 是    | Date                  | 标识JWT的过期时间     | 这里是一个Unix时间戳，默认5分钟                                                                                                                                                                                                                                                                                                                                                                                               |
| Payload | nbf    | 生效时间  | 否    | Date                  | 在此之前JWT不可用     | 暂未启用                                                                                                                                                                                                                                                                                                                                                                                                             |
| Payload | iat    | 签发时间  | 是    | Date                  | 标识JWT的签发时间     | Unix时间戳                                                                                                                                                                                                                                                                                                                                                                                                          |
| Payload | jti    | JWTID | 否    | String                | JWT唯一标识符，防重放攻击 | 暂未启用                                                                                                                                                                                                                                                                                                                                                                                                             |
| Payload | claims | 私有声明  | 否    | Map\<String, Object\> | 一个集合，可自定义字段    | 暂未启用                                                                                                                                                                                                                                                                                                                                                                                                             |
   
**签名（Signature）**
将上面的两个Base64编码后的字符串都用英文句号"."连接在一起（头部在前），就形成了：
```
eyJraWQiOiIyZWQ3YWQ4My0zYzhiLTQzYTktOTE2ZC1jOGI2ZWMyYzExNjUiLCJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIiLCJzdWIiOiIiLCJleHAiOjE3MTEwMjA0MTgsImlhdCI6MTcxMTAyMDExOCwianRpIjpudWxsLCJjbGFpbXMiOm51bGx9
```
将上面拼接完的字符串用RSA256算法进行加密。在加密的时候，还需要提供一个密钥（secret）。如果用mystar作为密钥的话，那么就可以得到加密后的内容：
```
eyJraWQiOiIyZWQ3YWQ4My0zYzhiLTQzYTktOTE2ZC1jOGI2ZWMyYzExNjUiLCJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIiLCJzdWIiOiIiLCJleHAiOjE3MTEwMjA0MTgsImlhdCI6MTcxMTAyMDExOCwianRpIjpudWxsLCJjbGFpbXMiOm51bGx9.
kQM1KhjZVvfjLSK8aaBX_4HdQNuaDCR1mkZxNWXa7PC38fSGDoPvIxo7kepy0XXM4m1DyJ_zwbC3cwDf5Fz54Lk0WvLe9ulrUqIO86AGeetWfLslRD7X5L_w3H-T7QKffCBlEnEagv_GBLjpxEMpraDTRTPpQu8ERIjRZVioHwQ1XDO1PChgpal1rhOmnF2rOE4ljVbN0VdbN2w2dLLPXhikLvwtEiXLnBKaaOuI7vtFMmWXwjBlqTIFbg39PVyWM4kEpPu2B9LaK5kNVW3OBkOLCP_triZMHlNZlHldEH9gHh2_h8xLKHpAthHXUWvDprtSwWBdWH2rDZlMW03rhnwpXg3ABknRUPNfrtTNy8HDvEGUVLmfkAdTs_D2y1RNt-MRn_fH50DiINOGi_Zf4uErrf5yHL1qln5cprID64ETctd0IuzhCp7weK1TlxzIGqGXClHf6_yjwJ2kC7Xikdk38Zx946ZNB32jdfWbJDZoUnL2v3_T3KThW21huLgB
```
最后，在上面生成的token上加一个前缀"Internal:"，用于标识此token的类型，最后得到的token是：
```
Internal:eyJraWQiOiIyZWQ3YWQ4My0zYzhiLTQzYTktOTE2ZC1jOGI2ZWMyYzExNjUiLCJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiIiLCJzdWIiOiIiLCJleHAiOjE3MTEwMjA0MTgsImlhdCI6MTcxMTAyMDExOCwianRpIjpudWxsLCJjbGFpbXMiOm51bGx9.kQM1KhjZVvfjLSK8aaBX_4HdQNuaDCR1mkZxNWXa7PC38fSGDoPvIxo7kepy0XXM4m1DyJ_zwbC3cwDf5Fz54Lk0WvLe9ulrUqIO86AGeetWfLslRD7X5L_w3H-T7QKffCBlEnEagv_GBLjpxEMpraDTRTPpQu8ERIjRZVioHwQ1XDO1PChgpal1rhOmnF2rOE4ljVbN0VdbN2w2dLLPXhikLvwtEiXLnBKaaOuI7vtFMmWXwjBlqTIFbg39PVyWM4kEpPu2B9LaK5kNVW3OBkOLCP_triZMHlNZlHldEH9gHh2_h8xLKHpAthHXUWvDprtSwWBdWH2rDZlMW03rhnwpXg3ABknRUPNfrtTNy8HDvEGUVLmfkAdTs_D2y1RNt-MRn_fH50DiINOGi_Zf4uErrf5yHL1qln5cprID64ETctd0IuzhCp7weK1TlxzIGqGXClHf6_yjwJ2kC7Xikdk38Zx946ZNB32jdfWbJDZoUnL2v3_T3KThW21huLgB
```
将上面的token在jwt网站（https://jwt.io/）上进行解析，可以看到具体的内容信息，如下：
图3解析内容   
![](https://support.huaweicloud.com/devg-craftartsipdcenter/figure/zh-cn_image_0000001834471552.png "点击放大")
**密钥**
上面的token在签名时需要用到一个密钥，方案采用了RSA非对称密钥算法，由私钥进行签名，公钥进行验证签名。此密钥对的生命周期由IPDCenter基础服务管理。由IPDCenter基础服务颁发密钥对，每个系统拥有自己的一对密钥，在颁发完成密钥后，IPDCenter将记录所有的公钥信息、密钥ID信息、APPID等信息。私钥则由应用自己保存。
**公钥获取**
公钥是用来检验token的，而且校验token时需要使用与私钥对应的公钥，因此，应用需要定时调用IPDCenter提供的接口，查询所有的公钥信息，加载到内存，检验token时找到对应的token进行检验。检验接口的规格如下：
接口地址：
https://域名/随机数文根/basic/mgmt/public/api/v1/keymanage/getPublicKeyList
接口header:
```
Authorization: 上面生成的token
Content-Type： application/json
```
接口body:
```
{
    "offset": 0,
    "limit": 2000
}
```
接口响应示例：
```
{
    "code": "IPDC.01020000",
    "datas": [
        {
            "appId": "121",
            "appName": "应用名称",
            "createTime": "2024-03-22T17:42:58.830872000",
            "creator": "xx",
            "isDeleteAble": "N",
            "keyId": "密钥ID, token中解析出密钥ID,根据ID找到对应的公钥,检验token是否合法",
            "publicKey": "公钥信息"
        }
    ],
    "message": "success",
    "totalCount": 3
}
```
