> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shannon.run/llms.txt
> Use this file to discover all available pages before exploring further.

# 身份验证

> Shannon 中的 API 密钥认证和授权

## 概述

<Note>关于 HTTP 请求头和示例，请参见 [/cn/api/rest/authentication](/cn/api/rest/authentication)。</Note>

Shannon 支持 API 密钥认证以保护对编排平台的访问。为了方便本地开发,身份验证**默认禁用**,可在生产部署时启用。

## 认证模式

### 开发模式(默认)

```bash theme={null}
# 在 .env 文件中
GATEWAY_SKIP_AUTH=1
```

在开发模式下:

* 不需要 API 密钥
* 所有请求都被接受
* 适用于本地测试和开发

### 生产模式

```bash theme={null}
# 在 .env 文件中
GATEWAY_SKIP_AUTH=0
```

在生产模式下:

* 所有请求都需要 API 密钥
* 无效的密钥返回 401 Unauthorized
* 对每个密钥实施速率限制

## API 密钥格式

Shannon 使用带前缀的 API 密钥:

```
sk_test_1234567890abcdef    # 测试密钥
sk_live_1234567890abcdef    # 生产密钥
```

<Warning>
  切勿将 API 密钥提交到版本控制系统或公开分享。
</Warning>

## 创建 API 密钥

### 通过命令行

```bash theme={null}
# 创建测试 API 密钥(从仓库根目录运行)
make seed-api-key

# 输出
✅ Test API key created. Use 'sk_test_123456' for testing.
Note: Authentication is disabled by default (GATEWAY_SKIP_AUTH=1)
```

### 通过 API

```bash theme={null}
curl -X POST http://localhost:8080/api/v1/auth/api-keys \
  -H "Authorization: Bearer <admin-token>" \
  -d '{
    "name": "My Application",
    "user_id": "user-123"
  }'
```

## 速率限制

Shannon 使用固定窗口计数器对每个 API 密钥实施速率限制:

### 默认限制

| 限制类型   | 默认值 |
| ------ | --- |
| 每分钟请求数 | 60  |
| 突发容许值  | 10  |

<Note>
  Token 预算和并发任务限制由编排器在工作流层级实施,而非在网关层。
</Note>

### 速率限制标头

响应包含当前窗口限制。当返回 429 时,会设置 `Retry-After`:

```http theme={null}
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1730001234
```

### 超过速率限制

当您超过速率限制时:

```bash theme={null}
HTTP/1.1 429 Too Many Requests
Retry-After: 30

{
  "error": "Rate limit exceeded",
  "message": "Too many requests. Please retry after the rate limit window resets."
}
```

### 处理速率限制

实施指数退避:

```python theme={null}
import time
import requests
from requests.exceptions import HTTPError

def submit_with_retry(query, max_retries=3):
    for attempt in range(max_retries):
        try:
            response = requests.post(
                "http://localhost:8080/api/v1/tasks",
                headers={"X-API-Key": "sk_test_123456"},
                json={"query": query}
            )
            response.raise_for_status()
            return response.json()

        except HTTPError as e:
            if e.response.status_code == 429:
                retry_after = int(e.response.headers.get('Retry-After', 60))
                print(f"Rate limited. Retrying after {retry_after}s...")
                time.sleep(retry_after)
            else:
                raise

    raise Exception("Max retries exceeded")
```

## 多租户

Shannon 支持具有租户隔离的多租户部署:

### 租户 ID

在请求中包含租户 ID:

```bash theme={null}
curl -X POST http://localhost:8080/api/v1/tasks \
  -H "X-API-Key: sk_test_123456" \
  -H "X-Tenant-ID: org-acme" \
  -H "Content-Type: application/json" \
  -d '{"query": "Process data"}'
```

### 租户隔离

每个租户都有:

* 隔离的会话存储
* 通过共享 Qdrant 集合中的负载过滤器(`tenant_id`)实现的每租户隔离
* 独立的预算跟踪
* 专用指标

## OPA 策略执行

Shannon 使用 [Open Policy Agent](https://www.openpolicyagent.org/) 进行细粒度访问控制:

### 策略结构

```rego theme={null}
package shannon.auth

import future.keywords.if

# Default deny
default allow = false

# Allow if user has valid API key and appropriate permissions
allow if {
    input.api_key_valid
    input.user.team in ["engineering", "data-science"]
    input.task.mode in allowed_modes[input.user.team]
}

# Team-specific allowed modes
allowed_modes := {
    "engineering": ["simple", "standard", "complex"],
    "data-science": ["standard", "complex"]
}

# Token budget limits by team
max_tokens[team] := 50000 if team == "data-science"
max_tokens[team] := 10000 if team == "engineering"
```

### 策略模式

在 `config/shannon.yaml` 中配置:

```yaml theme={null}
policy:
  enabled: true
  mode: "enforce"  # dry-run, enforce, off
  path: "/app/config/opa/policies"
  fail_closed: false  # Allow on policy errors
```

**模式:**

* `enforce`: 拒绝违反策略的请求
* `dry-run`: 记录违规但允许请求
* `off`: 禁用策略执行

### 示例: 限制模型

```rego theme={null}
package shannon.models

# Only allow specific models per team
allowed_models[user.team] contains model if {
    user.team == "cost-sensitive"
    model in ["gpt-5-mini", "claude-haiku"]
}

allowed_models[user.team] contains model if {
    user.team == "premium"
    model in ["gpt-5.1", "claude-opus", "gpt-5-mini", "claude-sonnet"]
}
```

## 安全最佳实践

### 1. 定期轮换密钥

```bash theme={null}
# 创建新密钥
make seed-api-key

# 用新密钥更新应用程序
# 迁移后撤销旧密钥
```

### 2. 使用环境变量

```python theme={null}
import os
from shannon import ShannonClient

client = ShannonClient(
    base_url=os.environ["SHANNON_BASE_URL"],
    api_key=os.environ["SHANNON_API_KEY"],
)
```

### 3. 在生产环境中启用 HTTPS

```yaml theme={null}
# config/shannon.yaml
gateway:
  tls:
    enabled: true
    cert_file: "/path/to/cert.pem"
    key_file: "/path/to/key.pem"
```

### 4. 监控 API 密钥使用情况

在 Prometheus 指标中跟踪使用情况:

```promql theme={null}
# Requests per API key
sum by (api_key_id) (rate(shannon_gateway_requests_total[5m]))

# Errors by API key
sum by (api_key_id) (rate(shannon_gateway_errors_total[5m]))
```

### 5. 实施 IP 白名单

```yaml theme={null}
# config/shannon.yaml
gateway:
  ip_whitelist:
    enabled: true
    allowed_ips:
      - "10.0.0.0/8"
      - "192.168.1.100"
```

## 故障排除

<AccordionGroup>
  <Accordion title="401 Unauthorized">
    **原因**: 缺少或无效的 API 密钥

    **解决方案**:

    ```bash theme={null}
    # 验证是否启用了身份验证
    grep GATEWAY_SKIP_AUTH .env

    # 如果已启用,检查您的 API 密钥
    curl -H "X-API-Key: sk_test_123456" \
      http://localhost:8080/api/v1/tasks
    ```
  </Accordion>

  <Accordion title="403 Forbidden">
    **原因**: API 密钥有效但权限不足(OPA 策略)

    **解决方案**: 检查 OPA 策略日志:

    ```bash theme={null}
    docker compose logs orchestrator | grep "policy"
    ```
  </Accordion>

  <Accordion title="429 Rate Limited">
    **原因**: 超过速率限制

    **解决方案**: 实施带指数退避的重试逻辑:

    ```python theme={null}
    retry_after = response.headers.get('Retry-After', 60)
    time.sleep(int(retry_after))
    ```
  </Accordion>

  <Accordion title="API 密钥不起作用">
    **原因**: 密钥可能已过期或被撤销

    **解决方案**: 创建新的测试密钥:

    ```bash theme={null}
    make seed-api-key
    ```
  </Accordion>
</AccordionGroup>

## 下一步

<CardGroup cols={2}>
  <Card title="提交任务" icon="paper-plane" href="/cn/api/rest/submit-task">
    了解如何使用身份验证提交任务
  </Card>

  <Card title="速率限制" icon="gauge" href="/cn/api/overview#rate-limiting">
    理解速率限制和配额
  </Card>

  <Card title="Python SDK" icon="python" href="/cn/sdk/python/quickstart">
    使用 SDK 进行自动身份验证
  </Card>

  <Card title="REST API 参考" icon="code" href="/cn/api/rest/overview">
    完整的 REST API 文档
  </Card>
</CardGroup>
