第 64 章

Admin API:组织 / 成员 / Workspace / API Key 的企业级管理完全指南

第六十四章:Admin API:组织管理、用户权限与 API Key 生命周期

64.1 Admin API 的定位与使用场景

Anthropic 的 Admin API(管理 API)是面向企业管理员的一组 REST 端点,允许以编程方式管理 Claude 的使用资源:组织设置、用户账户、Workspace 分配、API Key 生命周期、使用量查询。

相较于通过 Anthropic Console 手动管理,Admin API 在以下场景中不可替代:

Admin API 使用独立的 Admin Keysk-ant-admin-...),需与普通 API Key 区分存储和管理。

64.2 认证与基础配置

64.2.1 获取 Admin Key

Admin Key 只能由组织的 Owner 角色在 Anthropic Console 中创建:

  1. 登录 https://console.anthropic.com
  2. 进入 Settings → Admin Keys
  3. 点击 Create Admin Key,设置名称和过期时间
  4. 保存生成的 sk-ant-admin-... 密钥(只显示一次)

64.2.2 API 基础请求结构

所有 Admin API 请求使用相同的认证头:

import httpx
import os
from typing import Optional

ADMIN_BASE_URL = "https://api.anthropic.com/v1"
ADMIN_KEY = os.environ["ANTHROPIC_ADMIN_KEY"]  # sk-ant-admin-...

ADMIN_HEADERS = {
    "x-api-key": ADMIN_KEY,
    "anthropic-version": "2023-06-01",
    "content-type": "application/json"
}

class AnthropicAdminClient:
    """Anthropic Admin API 客户端"""
    
    def __init__(self, admin_key: Optional[str] = None):
        self.admin_key = admin_key or os.environ["ANTHROPIC_ADMIN_KEY"]
        self.base_url = ADMIN_BASE_URL
        self.headers = {
            "x-api-key": self.admin_key,
            "anthropic-version": "2023-06-01",
            "content-type": "application/json"
        }
        self.client = httpx.Client(timeout=30)
    
    def get(self, path: str, params: dict = None) -> dict:
        response = self.client.get(
            f"{self.base_url}{path}",
            headers=self.headers,
            params=params
        )
        response.raise_for_status()
        return response.json()
    
    def post(self, path: str, body: dict) -> dict:
        response = self.client.post(
            f"{self.base_url}{path}",
            headers=self.headers,
            json=body
        )
        response.raise_for_status()
        return response.json()
    
    def delete(self, path: str) -> dict:
        response = self.client.delete(
            f"{self.base_url}{path}",
            headers=self.headers
        )
        response.raise_for_status()
        return response.json()

64.3 组织管理(/v1/organizations)

64.3.1 获取组织信息

admin = AnthropicAdminClient()

# GET /v1/organizations
org_info = admin.get("/organizations")

请求:

GET https://api.anthropic.com/v1/organizations
x-api-key: sk-ant-admin-...
anthropic-version: 2023-06-01

响应示例:

{
  "id": "org_01XXXXXXXXXXXXXXXXXX",
  "name": "Acme Corporation",
  "created_at": "2024-01-15T08:00:00Z",
  "billing": {
    "plan": "enterprise",
    "usage_limit_usd": 10000.00,
    "current_month_usage_usd": 2345.67
  },
  "settings": {
    "default_model": "claude-opus-4-5",
    "require_mfa": true,
    "allowed_ip_ranges": ["203.0.113.0/24", "198.51.100.0/24"]
  }
}

64.3.2 更新组织设置

# PATCH /v1/organizations
updated = admin.post("/organizations", {
    "settings": {
        "require_mfa": True,
        "allowed_ip_ranges": ["203.0.113.0/24"]
    }
})

64.4 用户管理(/v1/users)

64.4.1 列出组织成员

# GET /v1/users - 分页列出所有用户
def list_all_users(admin: AnthropicAdminClient) -> list[dict]:
    """获取组织中的所有用户(处理分页)"""
    all_users = []
    after_cursor = None
    
    while True:
        params = {"limit": 100}  # 每页 100 条
        if after_cursor:
            params["after_id"] = after_cursor
        
        response = admin.get("/users", params=params)
        users = response.get("data", [])
        all_users.extend(users)
        
        # 检查是否有更多数据
        if not response.get("has_more", False):
            break
        
        # 获取最后一条记录的 ID 作为游标
        after_cursor = users[-1]["id"] if users else None
    
    return all_users

GET /v1/users 响应示例:

{
  "data": [
    {
      "id": "user_01XXXXXXXXXXXXXXXXXX",
      "email": "[email protected]",
      "name": "Alice Johnson",
      "role": "developer",
      "created_at": "2024-03-01T10:00:00Z",
      "last_active_at": "2025-04-27T15:30:00Z",
      "status": "active"
    },
    {
      "id": "user_02XXXXXXXXXXXXXXXXXX",
      "email": "[email protected]",
      "name": "Bob Smith",
      "role": "admin",
      "created_at": "2024-01-20T09:00:00Z",
      "last_active_at": "2025-04-28T08:00:00Z",
      "status": "active"
    }
  ],
  "has_more": true,
  "first_id": "user_01XXXXXXXXXXXXXXXXXX",
  "last_id": "user_02XXXXXXXXXXXXXXXXXX"
}

64.4.2 邀请新用户

# POST /v1/users/invite
def invite_user(admin: AnthropicAdminClient, email: str, role: str = "developer") -> dict:
    """
    邀请用户加入组织
    role: owner | admin | developer | billing
    """
    result = admin.post("/users/invite", {
        "email": email,
        "role": role
    })
    return result

请求 Body:

{
  "email": "[email protected]",
  "role": "developer"
}

响应示例:

{
  "id": "invite_01XXXXXXXXXXXXXXXXXX",
  "email": "[email protected]",
  "role": "developer",
  "status": "pending",
  "invited_at": "2025-04-28T10:00:00Z",
  "expires_at": "2025-05-05T10:00:00Z"
}

64.4.3 更新用户角色

# PATCH /v1/users/{user_id}
def update_user_role(admin: AnthropicAdminClient, user_id: str, new_role: str) -> dict:
    """修改用户角色"""
    import httpx
    
    response = admin.client.patch(
        f"{admin.base_url}/users/{user_id}",
        headers=admin.headers,
        json={"role": new_role}
    )
    response.raise_for_status()
    return response.json()

PATCH /v1/users/{user_id} 响应示例:

{
  "id": "user_01XXXXXXXXXXXXXXXXXX",
  "email": "[email protected]",
  "name": "Alice Johnson",
  "role": "admin",  // 已更新
  "updated_at": "2025-04-28T10:05:00Z"
}

64.4.4 移除用户

# DELETE /v1/users/{user_id}
def remove_user(admin: AnthropicAdminClient, user_id: str) -> dict:
    """从组织中移除用户(同时吊销其所有 API Key)"""
    return admin.delete(f"/users/{user_id}")

DELETE 响应:

{
  "id": "user_01XXXXXXXXXXXXXXXXXX",
  "deleted": true
}

64.5 API Key 生命周期管理(/v1/api_keys)

API Key 是 Claude 使用的核心凭据,其生命周期管理是 Admin API 最重要的功能之一。

64.5.1 列出 API Keys

# GET /v1/api_keys
def list_api_keys(admin: AnthropicAdminClient, workspace_id: Optional[str] = None) -> list[dict]:
    """列出所有 API Keys(可按 Workspace 过滤)"""
    params = {}
    if workspace_id:
        params["workspace_id"] = workspace_id
    
    response = admin.get("/api_keys", params=params)
    return response.get("data", [])

GET /v1/api_keys 响应示例:

{
  "data": [
    {
      "id": "apikey_01XXXXXXXXXXXXXXXXXX",
      "name": "Production Backend",
      "created_at": "2024-06-01T00:00:00Z",
      "last_used_at": "2025-04-28T09:45:00Z",
      "status": "active",
      "workspace_id": "workspace_01XXXXXXXXXXXXXXXX",
      "created_by": {
        "id": "user_01XXXXXXXXXXXXXXXXXX",
        "email": "[email protected]"
      },
      "partial_key": "sk-ant-api03-...ABCD"
    },
    {
      "id": "apikey_02XXXXXXXXXXXXXXXXXX",
      "name": "Dev Testing",
      "created_at": "2025-01-10T00:00:00Z",
      "last_used_at": "2025-04-20T14:30:00Z",
      "status": "active",
      "workspace_id": "workspace_02XXXXXXXXXXXXXXXX",
      "partial_key": "sk-ant-api03-...EFGH"
    }
  ],
  "has_more": false
}

64.5.2 创建新 API Key

# POST /v1/api_keys
def create_api_key(
    admin: AnthropicAdminClient,
    name: str,
    workspace_id: str,
    expires_at: Optional[str] = None
) -> dict:
    """
    创建新的 API Key
    注意:返回的完整密钥只显示一次,请立即保存
    """
    body = {
        "name": name,
        "workspace_id": workspace_id
    }
    if expires_at:
        body["expires_at"] = expires_at  # ISO 8601 格式
    
    result = admin.post("/api_keys", body)
    return result

POST /v1/api_keys 请求 Body:

{
  "name": "Customer Portal Service",
  "workspace_id": "workspace_01XXXXXXXXXXXXXXXX",
  "expires_at": "2026-04-28T00:00:00Z"
}

响应示例(包含完整密钥,仅此一次):

{
  "id": "apikey_03XXXXXXXXXXXXXXXXXX",
  "name": "Customer Portal Service",
  "key": "sk-ant-api03-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "workspace_id": "workspace_01XXXXXXXXXXXXXXXX",
  "created_at": "2025-04-28T10:10:00Z",
  "expires_at": "2026-04-28T00:00:00Z",
  "status": "active"
}

64.5.3 吊销 API Key

# DELETE /v1/api_keys/{api_key_id}
def revoke_api_key(admin: AnthropicAdminClient, api_key_id: str) -> dict:
    """立即吊销 API Key(使用该 Key 的所有请求将立即失败)"""
    return admin.delete(f"/api_keys/{api_key_id}")

DELETE 响应:

{
  "id": "apikey_01XXXXXXXXXXXXXXXXXX",
  "deleted": true
}

64.6 Workspace 管理(/v1/workspaces)

Workspace 是组织内的资源隔离单元,允许不同团队使用独立的 API Key 池和用量配额。

64.6.1 列出 Workspaces

# GET /v1/workspaces
def list_workspaces(admin: AnthropicAdminClient) -> list[dict]:
    response = admin.get("/workspaces")
    return response.get("data", [])

响应示例:

{
  "data": [
    {
      "id": "workspace_01XXXXXXXXXXXXXXXX",
      "name": "Production",
      "created_at": "2024-01-15T08:00:00Z",
      "usage_limits": {
        "monthly_spend_usd": 5000.00,
        "requests_per_minute": 1000
      }
    },
    {
      "id": "workspace_02XXXXXXXXXXXXXXXX",
      "name": "Development",
      "created_at": "2024-01-15T08:00:00Z",
      "usage_limits": {
        "monthly_spend_usd": 500.00,
        "requests_per_minute": 100
      }
    }
  ]
}

64.6.2 创建 Workspace

# POST /v1/workspaces
def create_workspace(
    admin: AnthropicAdminClient,
    name: str,
    monthly_spend_limit: float,
    rpm_limit: int = 100
) -> dict:
    """创建新 Workspace,设置用量限额"""
    return admin.post("/workspaces", {
        "name": name,
        "usage_limits": {
            "monthly_spend_usd": monthly_spend_limit,
            "requests_per_minute": rpm_limit
        }
    })

64.7 使用量查询与成本监控

64.7.1 获取使用量数据

# GET /v1/usage
def get_usage(
    admin: AnthropicAdminClient,
    start_date: str,  # YYYY-MM-DD
    end_date: str,
    workspace_id: Optional[str] = None,
    granularity: str = "day"  # hour | day | month
) -> dict:
    """获取指定时间范围的使用量数据"""
    params = {
        "start_date": start_date,
        "end_date": end_date,
        "granularity": granularity
    }
    if workspace_id:
        params["workspace_id"] = workspace_id
    
    return admin.get("/usage", params=params)

GET /v1/usage 响应示例:

{
  "data": [
    {
      "date": "2025-04-27",
      "input_tokens": 12345678,
      "output_tokens": 3456789,
      "cache_read_tokens": 987654,
      "cache_creation_tokens": 123456,
      "total_cost_usd": 456.78,
      "requests": 23456,
      "model_breakdown": {
        "claude-opus-4-5": {
          "input_tokens": 5000000,
          "output_tokens": 2000000,
          "cost_usd": 380.00
        },
        "claude-haiku-4-5": {
          "input_tokens": 7345678,
          "output_tokens": 1456789,
          "cost_usd": 76.78
        }
      }
    }
  ],
  "total": {
    "input_tokens": 12345678,
    "output_tokens": 3456789,
    "total_cost_usd": 456.78
  }
}

64.7.2 自动化成本告警

import smtplib
from email.mime.text import MIMEText
from datetime import datetime, timedelta

class CostAlertSystem:
    """基于 Admin API 的自动化成本告警系统"""
    
    def __init__(self, admin: AnthropicAdminClient, alert_threshold_usd: float):
        self.admin = admin
        self.threshold = alert_threshold_usd
    
    def check_and_alert(self):
        """检查本月用量,超过阈值时发送告警"""
        today = datetime.now()
        month_start = today.replace(day=1).strftime("%Y-%m-%d")
        today_str = today.strftime("%Y-%m-%d")
        
        usage = self.admin.get("/usage", params={
            "start_date": month_start,
            "end_date": today_str,
            "granularity": "month"
        })
        
        total_cost = usage.get("total", {}).get("total_cost_usd", 0)
        
        if total_cost > self.threshold:
            self._send_alert(total_cost)
            return True
        return False
    
    def _send_alert(self, current_cost: float):
        alert_message = f"""
【成本告警】Anthropic API 用量超出预算

当前月份用量:${current_cost:.2f} USD
告警阈值:${self.threshold:.2f} USD
超出比例:{((current_cost / self.threshold - 1) * 100):.1f}%

请登录 Anthropic Console 查看详细用量,并考虑:
1. 检查是否有异常调用
2. 调整 Workspace 用量限额
3. 优化高频接口的模型选择(使用 Haiku 替代 Opus)

此邮件由自动监控系统发送。
"""
        # 发送邮件告警(此处为简化示例)
        print(alert_message)

64.8 自动化入职/离职流程

结合 Admin API 的多个端点,构建完整的用户生命周期自动化。

class UserLifecycleManager:
    """自动化用户入职/离职管理"""
    
    def __init__(self, admin: AnthropicAdminClient):
        self.admin = admin
    
    def onboard_developer(
        self,
        email: str,
        name: str,
        team: str,
        workspace_id: str
    ) -> dict:
        """
        开发者入职流程:
        1. 邀请用户加入组织
        2. 为用户创建专属 API Key
        3. 返回凭据供发送给用户
        """
        # Step 1: 邀请用户
        invite = self.admin.post("/users/invite", {
            "email": email,
            "role": "developer"
        })
        
        # Step 2: 创建专属 API Key(有效期 1 年)
        from datetime import datetime, timedelta
        expires = (datetime.now() + timedelta(days=365)).isoformat() + "Z"
        
        api_key = create_api_key(
            self.admin,
            name=f"{name} - {team}",
            workspace_id=workspace_id,
            expires_at=expires
        )
        
        return {
            "invite_id": invite["id"],
            "invite_email": email,
            "api_key_id": api_key["id"],
            "api_key": api_key["key"],  # 只此一次,立即保存并安全传递给用户
            "workspace_id": workspace_id,
            "expires_at": expires
        }
    
    def offboard_developer(self, user_id: str) -> dict:
        """
        开发者离职流程:
        1. 列出并吊销该用户的所有 API Key
        2. 从组织移除用户
        """
        revoked_keys = []
        
        # 获取该用户的所有 API Key
        all_keys = list_api_keys(self.admin)
        user_keys = [k for k in all_keys if k.get("created_by", {}).get("id") == user_id]
        
        # 吊销所有 Key
        for key in user_keys:
            revoke_api_key(self.admin, key["id"])
            revoked_keys.append(key["id"])
        
        # 移除用户
        removal = self.admin.delete(f"/users/{user_id}")
        
        return {
            "user_id": user_id,
            "deleted": removal.get("deleted", False),
            "revoked_keys": revoked_keys,
            "revoked_count": len(revoked_keys)
        }

64.9 安全最佳实践

64.9.1 Admin Key 的保护

# Admin Key 安全存储示例(使用 AWS Secrets Manager)
import boto3
import json

def get_admin_key_from_secrets_manager(secret_name: str, region: str = "us-east-1") -> str:
    """从 AWS Secrets Manager 安全获取 Admin Key"""
    client = boto3.client("secretsmanager", region_name=region)
    response = client.get_secret_value(SecretId=secret_name)
    secret = json.loads(response["SecretString"])
    return secret["anthropic_admin_key"]

# 使用环境变量注入(CI/CD 推荐)
# export ANTHROPIC_ADMIN_KEY=$(aws secretsmanager get-secret-value ...)

64.9.2 操作审计日志

import logging
import functools
import time

logger = logging.getLogger("anthropic_admin_audit")

def audit_log(action: str):
    """Admin API 操作审计日志装饰器"""
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            start = time.time()
            result = None
            error = None
            
            try:
                result = func(*args, **kwargs)
                return result
            except Exception as e:
                error = str(e)
                raise
            finally:
                logger.info({
                    "action": action,
                    "timestamp": time.time(),
                    "elapsed_ms": int((time.time() - start) * 1000),
                    "args": str(args[1:])[:200],  # 排除 admin client
                    "success": error is None,
                    "error": error
                })
        return wrapper
    return decorator

@audit_log("invite_user")
def invite_user_audited(admin: AnthropicAdminClient, email: str, role: str) -> dict:
    return admin.post("/users/invite", {"email": email, "role": role})

@audit_log("revoke_api_key")
def revoke_api_key_audited(admin: AnthropicAdminClient, api_key_id: str) -> dict:
    return admin.delete(f"/api_keys/{api_key_id}")

小结

Admin API 为企业提供了对 Anthropic Claude 使用资源的完整程序化控制能力。核心端点包括:/v1/organizations(组织配置)、/v1/users(用户邀请/移除/角色变更)、/v1/api_keys(Key 创建/列出/吊销)、/v1/workspaces(资源隔离)、/v1/usage(用量与成本监控)。最佳实践是:Admin Key 存储在 Secrets Manager 而非代码中、所有操作记录审计日志、通过 Workspace 为不同团队设置独立限额、结合 /v1/usage 构建自动成本告警系统。用户生命周期管理(入职创建 Key、离职批量吊销)是最典型的自动化场景,能显著减少人工管理开销并降低离职后密钥残留的安全风险。

本章评分
4.5  / 5  (3 评分)

💬 留言讨论