Skip to content

认证授权

ChainlessChain API采用基于JWT的认证机制,确保API调用的安全性。

认证方式

1. API Token认证(推荐)

适用于服务端调用。

获取API Token

厂家管理系统:
系统设置 → API管理 → 创建Token

Token名称: 生产环境API
权限范围:
☑ 设备管理
☑ APP版本管理
□ 用户管理
□ 系统管理

有效期:
○ 30天
○ 90天
● 1年
○ 永久

创建Token →
复制保存: ccapi_1234567890abcdef...

使用Token

http
GET /api/v1/devices
Authorization: Bearer ccapi_1234567890abcdef...

2. OAuth 2.0

适用于第三方应用集成。

授权码流程

1. 重定向用户到授权页面
GET https://auth.chainlesschain.com/oauth/authorize
  ?client_id={client_id}
  &redirect_uri={redirect_uri}
  &response_type=code
  &scope=device:read device:write
  &state={random_state}

2. 用户授权后获取授权码
→ {redirect_uri}?code={authorization_code}&state={random_state}

3. 使用授权码换取访问令牌
POST https://auth.chainlesschain.com/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code={authorization_code}
&client_id={client_id}
&client_secret={client_secret}
&redirect_uri={redirect_uri}

响应:
{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "eyJhbGciOiJIUzI1NiIs...",
  "scope": "device:read device:write"
}

4. 使用访问令牌调用API
GET /api/v1/devices
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

3. 用户名密码

仅用于内部系统或测试环境。

http
POST /api/v1/auth/login
Content-Type: application/json

{
  "username": "admin",
  "password": "********"
}

响应:

json
{
  "code": 0,
  "message": "登录成功",
  "data": {
    "accessToken": "eyJhbGciOiJIUzI1NiIs...",
    "refreshToken": "eyJhbGciOiJIUzI1NiIs...",
    "expiresIn": 3600,
    "tokenType": "Bearer"
  }
}

JWT Token结构

json
{
  "alg": "HS256",
  "typ": "JWT"
}

Payload

json
{
  "sub": "user123",
  "iat": 1704096000,
  "exp": 1704099600,
  "scope": ["device:read", "device:write"],
  "iss": "chainlesschain.com",
  "aud": "api.chainlesschain.com"
}

Signature

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret
)

权限范围(Scopes)

设备管理

Scope说明权限
device:read读取设备信息查看设备列表、详情
device:write写入设备信息注册、激活、更新设备
device:delete删除设备删除、报废设备
device:manage管理设备所有设备操作权限

APP版本管理

Scope说明权限
app:read读取APP版本查看版本列表、详情
app:write上传APP版本上传新版本
app:publish发布APP版本发布版本到生产环境
app:manage管理APP版本所有版本操作权限

用户管理

Scope说明权限
user:read读取用户信息查看用户列表、详情
user:write写入用户信息创建、更新用户
user:delete删除用户删除用户账户
user:manage管理用户所有用户操作权限

系统管理

Scope说明权限
system:read读取系统信息查看系统配置、日志
system:write写入系统配置更新系统配置
system:manage管理系统所有系统操作权限

Token刷新

刷新访问令牌

http
POST /api/v1/auth/refresh
Content-Type: application/json

{
  "refreshToken": "eyJhbGciOiJIUzI1NiIs..."
}

响应:

json
{
  "code": 0,
  "data": {
    "accessToken": "eyJhbGciOiJIUzI1NiIs...",  // 新的访问令牌
    "refreshToken": "eyJhbGciOiJIUzI1NiIs...", // 新的刷新令牌
    "expiresIn": 3600
  }
}

自动刷新机制

typescript
class APIClient {
    private accessToken: string
    private refreshToken: string
    private expiresAt: number

    async request(url: string, options: RequestInit) {
        // 检查token是否即将过期(提前5分钟刷新)
        if (Date.now() + 300000 >= this.expiresAt) {
            await this.refreshAccessToken()
        }

        return fetch(url, {
            ...options,
            headers: {
                ...options.headers,
                'Authorization': `Bearer ${this.accessToken}`
            }
        })
    }

    private async refreshAccessToken() {
        const response = await fetch('/api/v1/auth/refresh', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ refreshToken: this.refreshToken })
        })

        const data = await response.json()
        this.accessToken = data.data.accessToken
        this.refreshToken = data.data.refreshToken
        this.expiresAt = Date.now() + data.data.expiresIn * 1000
    }
}

错误处理

认证错误码

错误码HTTP状态码说明解决方法
401001401Token缺失提供Authorization头
401002401Token无效使用有效的Token
401003401Token过期刷新Token
401004401签名错误检查Token完整性
403001403权限不足申请相应权限
403002403Scope不足扩展Scope范围
429001429请求过于频繁降低请求频率

错误响应示例

json
{
  "code": 401003,
  "message": "Token已过期",
  "error": "token_expired",
  "timestamp": "2024-01-15T10:30:00Z",
  "path": "/api/v1/devices"
}

速率限制

限制策略

Token类型限制时间窗口
API Token1000次1小时
OAuth Token500次1小时
用户登录100次1小时

响应头

http
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 995
X-RateLimit-Reset: 1704099600

超出限制

http
HTTP/1.1 429 Too Many Requests
Retry-After: 1800

{
  "code": 429001,
  "message": "请求过于频繁,请稍后再试",
  "retryAfter": 1800
}

安全最佳实践

1. Token安全

typescript
// ✅ 推荐:存储在环境变量
const apiToken = process.env.CHAINLESSCHAIN_API_TOKEN

// ❌ 不推荐:硬编码在代码中
const apiToken = 'ccapi_1234567890abcdef...'

// ✅ 推荐:使用HTTPS
const apiUrl = 'https://api.chainlesschain.com'

// ❌ 不推荐:使用HTTP
const apiUrl = 'http://api.chainlesschain.com'

2. Token轮换

定期轮换API Token:
- 生产环境: 每90天
- 测试环境: 每30天
- 开发环境: 根据需要

设置提醒:
系统设置 → API管理 → Token过期提醒

3. 最小权限原则

只申请必要的权限:

// ✅ 推荐:最小权限
scopes: ['device:read']

// ❌ 不推荐:过度权限
scopes: ['device:manage', 'user:manage', 'system:manage']

4. IP白名单

系统设置 → API管理 → IP白名单

添加允许的IP:
- 192.168.1.100
- 10.0.0.0/24
- 2001:db8::/32

启用IP白名单验证

示例代码

JavaScript/Node.js

javascript
const axios = require('axios')

const client = axios.create({
    baseURL: 'https://api.chainlesschain.com/api/v1',
    headers: {
        'Authorization': `Bearer ${process.env.API_TOKEN}`,
        'Content-Type': 'application/json'
    }
})

// 带自动重试的请求
async function requestWithRetry(config, maxRetries = 3) {
    for (let i = 0; i < maxRetries; i++) {
        try {
            return await client(config)
        } catch (error) {
            if (error.response?.status === 401 && i < maxRetries - 1) {
                // Token过期,刷新后重试
                await refreshToken()
                continue
            }
            throw error
        }
    }
}

// 使用示例
const devices = await requestWithRetry({ url: '/devices' })

Python

python
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

class ChainlessChainAPI:
    def __init__(self, api_token):
        self.base_url = 'https://api.chainlesschain.com/api/v1'
        self.session = requests.Session()
        self.session.headers.update({
            'Authorization': f'Bearer {api_token}',
            'Content-Type': 'application/json'
        })

        # 配置自动重试
        retry = Retry(
            total=3,
            backoff_factor=0.3,
            status_forcelist=[500, 502, 503, 504]
        )
        adapter = HTTPAdapter(max_retries=retry)
        self.session.mount('https://', adapter)

    def get_devices(self, page=1, size=20):
        response = self.session.get(
            f'{self.base_url}/devices',
            params={'page': page, 'size': size}
        )
        response.raise_for_status()
        return response.json()

# 使用示例
api = ChainlessChainAPI(os.getenv('API_TOKEN'))
devices = api.get_devices()

测试工具

Postman配置

json
{
  "info": {
    "name": "ChainlessChain API",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{api_token}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://api.chainlesschain.com/api/v1"
    },
    {
      "key": "api_token",
      "value": "ccapi_1234567890abcdef..."
    }
  ]
}

cURL示例

bash
# 获取设备列表
curl -X GET "https://api.chainlesschain.com/api/v1/devices?page=1&size=20" \
  -H "Authorization: Bearer ccapi_1234567890abcdef..." \
  -H "Content-Type: application/json"

# 注册设备
curl -X POST "https://api.chainlesschain.com/api/v1/devices/register" \
  -H "Authorization: Bearer ccapi_1234567890abcdef..." \
  -H "Content-Type: application/json" \
  -d '{
    "deviceType": "U盾",
    "model": "ePass3003",
    "serialNumber": "UP2024010100001"
  }'

常见问题

Token在哪里获取?

登录厂家管理系统 → 系统设置 → API管理 → 创建Token

Token可以分享吗?

不可以。Token相当于密码,不应分享给他人。每个应用/服务应使用独立的Token。

如何撤销Token?

系统设置 → API管理 → Token列表 → 点击"撤销"

忘记Token怎么办?

Token不可找回,只能重新生成。建议妥善保管。

基于 MIT 许可发布