# 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` ### 模式类型 ```typescript type PermissionMode = | 'default' // 标准交互式权限确认 | 'plan' // 计划模式,只读操作 | 'bypassPermissions' // 跳过所有权限检查 | 'auto' // 自动批准基于分类器 | 'localAssistant' // 本地助手模式 ``` ### 模式转换 ```typescript export function transitionPermissionMode( from: PermissionMode, to: PermissionMode, options?: { skipAutoGate?: boolean } ): { ok: true } | { ok: false; error: string } ``` --- ## 2. PermissionContext - 权限上下文 **文件位置**: `src/hooks/toolPermission/PermissionContext.ts` ### 创建权限上下文 ```typescript function createPermissionContext( tool: ToolType, input: Record, toolUseContext: ToolUseContext, assistantMessage: AssistantMessage, toolUseID: string, setToolPermissionContext: (context: ToolPermissionContext) => void, queueOps?: PermissionQueueOps, ) ``` ### 上下文方法 ```typescript type PermissionContext = { // 工具信息 tool: ToolType input: Record toolUseContext: ToolUseContext assistantMessage: AssistantMessage messageId: string toolUseID: string // 日志记录 logDecision(args: PermissionDecisionArgs, opts?: {...}): void logCancelled(): void // 权限持久化 async persistPermissions(updates: PermissionUpdate[]): Promise // 决策构建 buildAllow( updatedInput: Record, opts?: {...} ): PermissionAllowDecision buildDeny( message: string, decisionReason: PermissionDecisionReason ): PermissionDenyDecision // 用户处理 async handleUserAllow( updatedInput: Record, permissionUpdates: PermissionUpdate[], feedback?: string, ... ): Promise // Hook 执行 async runHooks( permissionMode: string | undefined, suggestions: PermissionUpdate[] | undefined, updatedInput?: Record, ... ): Promise // 分类器尝试 async tryClassifier( pendingClassifierCheck: PendingClassifierCheck | undefined, updatedInput: Record | undefined ): Promise // 队列操作 pushToQueue(item: ToolUseConfirm): void removeFromQueue(): void updateQueueItem(patch: Partial): void // 中止处理 resolveIfAbort(resolve: (decision: PermissionDecision) => void): boolean cancelAndAbort( feedback?: string, isAbort?: boolean, contentBlocks?: ContentBlockParam[] ): PermissionDecision } ``` --- ## 3. 权限决策类型 **文件位置**: `src/types/permissions.ts` ### 决策类型 ```typescript type PermissionDecision = | { behavior: 'allow'; updatedInput?: Record; ... } | { behavior: 'deny'; message: string; ... } | { behavior: 'ask' } | { behavior: 'skip' } ``` ### 决策来源 ```typescript type PermissionDecisionSource = | { type: 'hook'; permanent?: boolean } | { type: 'user'; permanent: boolean } | { type: 'classifier' } | 'config' // 配置自动允许 ``` ### 待处理分类器检查 ```typescript type PendingClassifierCheck = { input: Record command: string // ... } ``` --- ## 4. 权限处理器 ### 4.1 Coordinator Handler **文件位置**: `src/hooks/toolPermission/handlers/coordinatorHandler.ts` 用于协调者工作进程(coordinator worker)的权限处理流程。 ```typescript async function handleCoordinatorPermission( params: CoordinatorPermissionParams ): Promise ``` **处理流程**: 1. **尝试权限 Hooks**(快速,本地) ```typescript const hookResult = await ctx.runHooks( permissionMode, suggestions, updatedInput ) if (hookResult) return hookResult ``` 2. **尝试分类器**(慢速,推理) ```typescript const classifierResult = feature('BASH_CLASSIFIER') ? await ctx.tryClassifier?.(pendingClassifierCheck, updatedInput) : null if (classifierResult) return classifierResult ``` 3. **降级到交互式对话框** ```typescript return null // 交给交互式处理 ``` ### 4.2 Interactive Handler **文件位置**: `src/hooks/toolPermission/handlers/interactiveHandler.ts` 用于主代理的交互式权限处理。 ```typescript function handleInteractivePermission( params: InteractivePermissionParams, resolve: (decision: PermissionDecision) => void, ): void ``` **处理流程**: 1. **推送确认队列项** ```typescript ctx.pushToQueue({ assistantMessage, tool, description, input: displayInput, toolUseID, permissionResult: result, permissionPromptStartTimeMs, onUserInteraction: () => { ... }, onAbort: () => { ... }, onAllow: () => { ... }, onReject: () => { ... }, recheckPermission: () => { ... }, }) ``` 2. **桥接权限转发**(远程控制) ```typescript if (bridgeCallbacks && bridgeRequestId) { bridgeCallbacks.sendRequest( bridgeRequestId, ctx.tool.name, displayInput, ctx.toolUseID, description, result.suggestions, result.blockedPath ) } ``` 3. **通道权限转发**(KAIROS) ```typescript if (channelCallbacks && !ctx.tool.requiresUserInteraction?.()) { // 发送到通道(Telegram, iMessage 等) client.notification({ method: CHANNEL_PERMISSION_REQUEST_METHOD, params }) } ``` 4. **异步 Hook 执行** ```typescript void (async () => { const hookDecision = await ctx.runHooks(...) if (hookDecision && claim()) { resolveOnce(hookDecision) } })() ``` 5. **异步分类器执行** ```typescript 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` ### 回调接口 ```typescript type BridgePermissionCallbacks = { sendRequest( requestId: string, toolName: string, input: Record, 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 } ``` ### 权限响应 ```typescript type BridgePermissionResponse = { behavior: 'allow' | 'deny' updatedInput?: Record updatedPermissions?: PermissionUpdate[] message?: string } ``` --- ## 6. 权限规则管理 ### 6.1 PermissionUpdate **文件位置**: `src/utils/permissions/PermissionUpdateSchema.ts` ```typescript type PermissionUpdate = { destination: 'alwaysAllowRules' | 'alwaysDenyRules' | 'command' rule: { tool: string input?: Record matchers?: InputMatcher[] } Permanente: boolean } ``` ### 6.2 规则应用 ```typescript export function applyPermissionUpdates( context: ToolPermissionContext, updates: PermissionUpdate[] ): ToolPermissionContext ``` ### 6.3 规则持久化 ```typescript export function persistPermissionUpdates(updates: PermissionUpdate[]): void export function supportsPersistence( destination: 'alwaysAllowRules' | 'alwaysDenyRules' | 'command' ): boolean ``` --- ## 7. Bash 分类器 **文件位置**: `src/tools/BashTool/bashPermissions.ts` ### 分类器决策 ```typescript 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 } ``` ### 分类器检查 ```typescript export async function awaitClassifierAutoApproval( pendingClassifierCheck: PendingClassifierCheck, signal: AbortSignal, isNonInteractiveSession: boolean, ): Promise ``` --- ## 8. 权限日志 **文件位置**: `src/hooks/toolPermission/permissionLogging.ts` ### 日志函数 ```typescript export function logPermissionDecision( args: PermissionDecisionArgs, decision: { decision: 'accept' | 'reject' source: PermissionApprovalSource | PermissionRejectionSource }, permissionPromptStartTimeMs?: number ): void ``` ### 事件类型 ```typescript // 接受 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` ### 主检查函数 ```typescript export async function hasPermissionsToUseTool( tool: Tool, input: Record, toolUseContext: ToolUseContext, assistantMessage: AssistantMessage, toolUseID: string, ): Promise ``` **决策流程**: 1. **模式检查** - `bypassPermissions`: 直接允许 - `plan`: 计划模式规则 - `auto`: 分类器自动决策 2. **规则匹配** - `alwaysAllowRules`: 匹配则允许 - `alwaysDenyRules`: 匹配则拒绝 3. **会话状态** - 非交互式会话可能有不同行为 4. **分类器检查** - 仅 Bash 工具支持 - 异步执行 5. **Hook 检查** - 执行 PermissionRequest hooks 6. **降级到交互式** - 返回 `{ behavior: 'ask' }` --- ## 10. 权限队列 ### ToolUseConfirm ```typescript type ToolUseConfirm = { assistantMessage: AssistantMessage tool: Tool description: string input: Record 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, permissionUpdates: PermissionUpdate[], feedback?: string, contentBlocks?: ContentBlockParam[] ): Promise onReject(feedback?: string, contentBlocks?: ContentBlockParam[]): void recheckPermission(): Promise } ``` --- ## 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. 关键常量 ```typescript // 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` | 权限类型定义 |