Files
2026-04-03 13:01:19 +08:00

17 KiB
Raw Permalink Blame History

Claude Code 权限系统详解

概述

Claude Code 的权限系统管理工具调用的授权流程。当 Claude 尝试执行危险操作(如运行 Bash 命令、写入文件)时,系统会请求用户确认。权限系统支持多种授权模式和来源,确保用户对工具执行有完全控制。


核心架构

┌─────────────────────────────────────────────────────────────────┐
│                     权限请求入口                                 │
│                                                                  │
│  hasPermissionsToUseTool(tool, input, context, message, id)    │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                    权限模式检查 (PermissionMode)                 │
│                                                                  │
│  default | plan | bypassPermissions | auto | localAssistant     │
└─────────────────────────────────────────────────────────────────┘
                              │
              ┌───────────────┼───────────────┐
              ▼               ▼               ▼
      ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
      │   Coordinator │ │  Interactive │ │ Swarm Worker │
      │    Handler   │ │   Handler    │ │   Handler    │
      └──────────────┘ └──────────────┘ └──────────────┘
              │               │               │
              └───────────────┼───────────────┘
                              ▼
              ┌──────────────────────────────────────┐
              │           权限决策结果               │
              │                                      │
              │  allow | deny | ask | skip          │
              └──────────────────────────────────────┘

1. 权限模式 (PermissionMode)

文件位置: src/utils/permissions/PermissionMode.ts

模式类型

type PermissionMode =
  | 'default'        // 标准交互式权限确认
  | 'plan'           // 计划模式,只读操作
  | 'bypassPermissions'  // 跳过所有权限检查
  | 'auto'           // 自动批准基于分类器
  | 'localAssistant' // 本地助手模式

模式转换

export function transitionPermissionMode(
  from: PermissionMode,
  to: PermissionMode,
  options?: { skipAutoGate?: boolean }
): { ok: true } | { ok: false; error: string }

2. PermissionContext - 权限上下文

文件位置: src/hooks/toolPermission/PermissionContext.ts

创建权限上下文

function createPermissionContext(
  tool: ToolType,
  input: Record<string, unknown>,
  toolUseContext: ToolUseContext,
  assistantMessage: AssistantMessage,
  toolUseID: string,
  setToolPermissionContext: (context: ToolPermissionContext) => void,
  queueOps?: PermissionQueueOps,
)

上下文方法

type PermissionContext = {
  // 工具信息
  tool: ToolType
  input: Record<string, unknown>
  toolUseContext: ToolUseContext
  assistantMessage: AssistantMessage
  messageId: string
  toolUseID: string

  // 日志记录
  logDecision(args: PermissionDecisionArgs, opts?: {...}): void
  logCancelled(): void

  // 权限持久化
  async persistPermissions(updates: PermissionUpdate[]): Promise<boolean>

  // 决策构建
  buildAllow(
    updatedInput: Record<string, unknown>,
    opts?: {...}
  ): PermissionAllowDecision

  buildDeny(
    message: string,
    decisionReason: PermissionDecisionReason
  ): PermissionDenyDecision

  // 用户处理
  async handleUserAllow(
    updatedInput: Record<string, unknown>,
    permissionUpdates: PermissionUpdate[],
    feedback?: string,
    ...
  ): Promise<PermissionAllowDecision>

  // Hook 执行
  async runHooks(
    permissionMode: string | undefined,
    suggestions: PermissionUpdate[] | undefined,
    updatedInput?: Record<string, unknown>,
    ...
  ): Promise<PermissionDecision | null>

  // 分类器尝试
  async tryClassifier(
    pendingClassifierCheck: PendingClassifierCheck | undefined,
    updatedInput: Record<string, unknown> | undefined
  ): Promise<PermissionDecision | null>

  // 队列操作
  pushToQueue(item: ToolUseConfirm): void
  removeFromQueue(): void
  updateQueueItem(patch: Partial<ToolUseConfirm>): void

  // 中止处理
  resolveIfAbort(resolve: (decision: PermissionDecision) => void): boolean
  cancelAndAbort(
    feedback?: string,
    isAbort?: boolean,
    contentBlocks?: ContentBlockParam[]
  ): PermissionDecision
}

3. 权限决策类型

文件位置: src/types/permissions.ts

决策类型

type PermissionDecision =
  | { behavior: 'allow'; updatedInput?: Record<string, unknown>; ... }
  | { behavior: 'deny'; message: string; ... }
  | { behavior: 'ask' }
  | { behavior: 'skip' }

决策来源

type PermissionDecisionSource =
  | { type: 'hook'; permanent?: boolean }
  | { type: 'user'; permanent: boolean }
  | { type: 'classifier' }
  | 'config'  // 配置自动允许

待处理分类器检查

type PendingClassifierCheck = {
  input: Record<string, unknown>
  command: string
  // ...
}

4. 权限处理器

4.1 Coordinator Handler

文件位置: src/hooks/toolPermission/handlers/coordinatorHandler.ts

用于协调者工作进程coordinator worker的权限处理流程。

async function handleCoordinatorPermission(
  params: CoordinatorPermissionParams
): Promise<PermissionDecision | null>

处理流程:

  1. 尝试权限 Hooks(快速,本地)

    const hookResult = await ctx.runHooks(
      permissionMode,
      suggestions,
      updatedInput
    )
    if (hookResult) return hookResult
    
  2. 尝试分类器(慢速,推理)

    const classifierResult = feature('BASH_CLASSIFIER')
      ? await ctx.tryClassifier?.(pendingClassifierCheck, updatedInput)
      : null
    if (classifierResult) return classifierResult
    
  3. 降级到交互式对话框

    return null  // 交给交互式处理
    

4.2 Interactive Handler

文件位置: src/hooks/toolPermission/handlers/interactiveHandler.ts

用于主代理的交互式权限处理。

function handleInteractivePermission(
  params: InteractivePermissionParams,
  resolve: (decision: PermissionDecision) => void,
): void

处理流程:

  1. 推送确认队列项

    ctx.pushToQueue({
      assistantMessage,
      tool,
      description,
      input: displayInput,
      toolUseID,
      permissionResult: result,
      permissionPromptStartTimeMs,
      onUserInteraction: () => { ... },
      onAbort: () => { ... },
      onAllow: () => { ... },
      onReject: () => { ... },
      recheckPermission: () => { ... },
    })
    
  2. 桥接权限转发(远程控制)

    if (bridgeCallbacks && bridgeRequestId) {
      bridgeCallbacks.sendRequest(
        bridgeRequestId,
        ctx.tool.name,
        displayInput,
        ctx.toolUseID,
        description,
        result.suggestions,
        result.blockedPath
      )
    }
    
  3. 通道权限转发KAIROS

    if (channelCallbacks && !ctx.tool.requiresUserInteraction?.()) {
      // 发送到通道Telegram, iMessage 等)
      client.notification({
        method: CHANNEL_PERMISSION_REQUEST_METHOD,
        params
      })
    }
    
  4. 异步 Hook 执行

    void (async () => {
      const hookDecision = await ctx.runHooks(...)
      if (hookDecision && claim()) {
        resolveOnce(hookDecision)
      }
    })()
    
  5. 异步分类器执行

    if (feature('BASH_CLASSIFIER') && result.pendingClassifierCheck) {
      setClassifierChecking(ctx.toolUseID)
      void executeAsyncClassifierCheck(...)
    }
    

4.3 Swarm Worker Handler

文件位置: src/hooks/toolPermission/handlers/swarmWorkerHandler.ts

用于 Swarm Worker 的权限处理(简化的仅拒绝处理)。


5. 权限回调 (Bridge Permission Callbacks)

文件位置: src/bridge/bridgePermissionCallbacks.ts

回调接口

type BridgePermissionCallbacks = {
  sendRequest(
    requestId: string,
    toolName: string,
    input: Record<string, unknown>,
    toolUseId: string,
    description: string,
    permissionSuggestions?: PermissionUpdate[],
    blockedPath?: string,
  ): void

  sendResponse(requestId: string, response: BridgePermissionResponse): void

  cancelRequest(requestId: string): void

  onResponse(
    requestId: string,
    handler: (response: BridgePermissionResponse) => void,
  ): () => void
}

权限响应

type BridgePermissionResponse = {
  behavior: 'allow' | 'deny'
  updatedInput?: Record<string, unknown>
  updatedPermissions?: PermissionUpdate[]
  message?: string
}

6. 权限规则管理

6.1 PermissionUpdate

文件位置: src/utils/permissions/PermissionUpdateSchema.ts

type PermissionUpdate = {
  destination: 'alwaysAllowRules' | 'alwaysDenyRules' | 'command'
  rule: {
    tool: string
    input?: Record<string, unknown>
    matchers?: InputMatcher[]
  }
  Permanente: boolean
}

6.2 规则应用

export function applyPermissionUpdates(
  context: ToolPermissionContext,
  updates: PermissionUpdate[]
): ToolPermissionContext

6.3 规则持久化

export function persistPermissionUpdates(updates: PermissionUpdate[]): void
export function supportsPersistence(
  destination: 'alwaysAllowRules' | 'alwaysDenyRules' | 'command'
): boolean

7. Bash 分类器

文件位置: src/tools/BashTool/bashPermissions.ts

分类器决策

type ClassifierDecision =
  | { type: 'classifier'; classifier: 'auto-mode'; reason: string }
  | { type: 'classifier'; classifier: 'pattern-match'; reason: string }
  | { type: 'user-defined'; reason: string }
  | { type: 'deny'; reason: string }

分类器检查

export async function awaitClassifierAutoApproval(
  pendingClassifierCheck: PendingClassifierCheck,
  signal: AbortSignal,
  isNonInteractiveSession: boolean,
): Promise<ClassifierDecision | null>

8. 权限日志

文件位置: src/hooks/toolPermission/permissionLogging.ts

日志函数

export function logPermissionDecision(
  args: PermissionDecisionArgs,
  decision: {
    decision: 'accept' | 'reject'
    source: PermissionApprovalSource | PermissionRejectionSource
  },
  permissionPromptStartTimeMs?: number
): void

事件类型

// 接受
logEvent('tengu_tool_permission_accepted', {...})
logEvent('tengu_tool_permission_auto_approved', {...})

// 拒绝
logEvent('tengu_tool_permission_rejected', {...})
logEvent('tengu_tool_use_cancelled', {...})

9. 权限检查入口

文件位置: src/utils/permissions/permissions.ts

主检查函数

export async function hasPermissionsToUseTool(
  tool: Tool,
  input: Record<string, unknown>,
  toolUseContext: ToolUseContext,
  assistantMessage: AssistantMessage,
  toolUseID: string,
): Promise<PermissionDecision>

决策流程:

  1. 模式检查

    • bypassPermissions: 直接允许
    • plan: 计划模式规则
    • auto: 分类器自动决策
  2. 规则匹配

    • alwaysAllowRules: 匹配则允许
    • alwaysDenyRules: 匹配则拒绝
  3. 会话状态

    • 非交互式会话可能有不同行为
  4. 分类器检查

    • 仅 Bash 工具支持
    • 异步执行
  5. Hook 检查

    • 执行 PermissionRequest hooks
  6. 降级到交互式

    • 返回 { behavior: 'ask' }

10. 权限队列

ToolUseConfirm

type ToolUseConfirm = {
  assistantMessage: AssistantMessage
  tool: Tool
  description: string
  input: Record<string, unknown>
  toolUseContext: ToolUseContext
  toolUseID: string
  permissionResult: PermissionDecision & { behavior: 'ask' }
  permissionPromptStartTimeMs: number
  classifierCheckInProgress?: boolean
  classifierAutoApproved?: boolean
  classifierMatchedRule?: string

  onUserInteraction(): void
  onDismissCheckmark(): void
  onAbort(): void
  onAllow(
    updatedInput: Record<string, unknown>,
    permissionUpdates: PermissionUpdate[],
    feedback?: string,
    contentBlocks?: ContentBlockParam[]
  ): Promise<void>
  onReject(feedback?: string, contentBlocks?: ContentBlockParam[]): void
  recheckPermission(): Promise<void>
}

11. 权限处理流程图

用户执行工具
     │
     ▼
hasPermissionsToUseTool()
     │
     ▼
┌─────────────────────┐
│ 权限模式检查        │
│ bypassPermissions?  │ ───是──▶ 直接允许
└─────────────────────┘
     │否
     ▼
┌─────────────────────┐
│ 规则检查           │
│ alwaysAllowRules?   │ ───是──▶ 直接允许
│ alwaysDenyRules?    │ ───是──▶ 直接拒绝
└─────────────────────┘
     │
     ▼
┌─────────────────────┐
│ 分类器检查          │
│ BASH_CLASSIFIER?    │ ───是──▶ 异步推理
└─────────────────────┘
     │
     ▼
┌─────────────────────┐
│ Hook 检查           │
│ executePermission   │ ───允许──▶ 返回允许
│ RequestHooks        │ ───拒绝──▶ 返回拒绝
└─────────────────────┘
     │
     ▼
交互式确认对话框
     │
     ├─── 用户允许 ───▶ handleUserAllow()
     │                      │
     │                      ▼
     │                 persistPermissions()
     │                      │
     │                      ▼
     │                 logPermissionDecision()
     │                      │
     │                      ▼
     │                 返回 PermissionAllowDecision
     │
     ├─── 用户拒绝 ───▶ onReject()
     │                      │
     │                      ▼
     │                 cancelAndAbort()
     │                      │
     │                      ▼
     │                 返回 PermissionDenyDecision
     │
     └─── 用户中断 ───▶ Esc 按键
                            │
                            ▼
                       abortController.abort()
                            │
                            ▼
                       返回 PermissionDenyDecision

12. 远程权限流程

CLI 端 (handleInteractivePermission)
     │
     ▼
bridgeCallbacks.sendRequest(bridgeRequestId, ...)
     │
     │ WebSocket / HTTP
     ▼
IDE Extension / Web UI
     │
     ▼
显示权限对话框
     │
     ▼
用户允许/拒绝
     │
     ▼
bridgeCallbacks.sendResponse(bridgeRequestId, response)
     │
     │ WebSocket / HTTP
     ▼
CLI 端 (onResponse 回调)
     │
     ▼
resolveOnce(decision)

13. 关键常量

// 200ms 宽限期后用户交互取消分类器
const GRACE_PERIOD_MS = 200

// 分类器自动批准后显示 ✓ 的时间
const CHECKMARK_DISPLAY_MS = 3000  // 终端聚焦时
const CHECKMARK_DISPLAY_MS = 1000  // 终端未聚焦时

相关源码文件

文件 功能
PermissionContext.ts 权限上下文创建和管理
handlers/coordinatorHandler.ts 协调者处理器
handlers/interactiveHandler.ts 交互式处理器
handlers/swarmWorkerHandler.ts Swarm Worker 处理器
permissionLogging.ts 权限日志记录
src/utils/permissions/permissions.ts 权限检查入口
src/utils/permissions/PermissionUpdate.ts 权限更新管理
src/utils/permissions/PermissionMode.ts 权限模式定义
src/bridge/bridgePermissionCallbacks.ts 桥接权限回调
src/tools/BashTool/bashPermissions.ts Bash 分类器
src/types/permissions.ts 权限类型定义