17 KiB
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>
处理流程:
-
尝试权限 Hooks(快速,本地)
const hookResult = await ctx.runHooks( permissionMode, suggestions, updatedInput ) if (hookResult) return hookResult -
尝试分类器(慢速,推理)
const classifierResult = feature('BASH_CLASSIFIER') ? await ctx.tryClassifier?.(pendingClassifierCheck, updatedInput) : null if (classifierResult) return classifierResult -
降级到交互式对话框
return null // 交给交互式处理
4.2 Interactive Handler
文件位置: src/hooks/toolPermission/handlers/interactiveHandler.ts
用于主代理的交互式权限处理。
function handleInteractivePermission(
params: InteractivePermissionParams,
resolve: (decision: PermissionDecision) => void,
): void
处理流程:
-
推送确认队列项
ctx.pushToQueue({ assistantMessage, tool, description, input: displayInput, toolUseID, permissionResult: result, permissionPromptStartTimeMs, onUserInteraction: () => { ... }, onAbort: () => { ... }, onAllow: () => { ... }, onReject: () => { ... }, recheckPermission: () => { ... }, }) -
桥接权限转发(远程控制)
if (bridgeCallbacks && bridgeRequestId) { bridgeCallbacks.sendRequest( bridgeRequestId, ctx.tool.name, displayInput, ctx.toolUseID, description, result.suggestions, result.blockedPath ) } -
通道权限转发(KAIROS)
if (channelCallbacks && !ctx.tool.requiresUserInteraction?.()) { // 发送到通道(Telegram, iMessage 等) client.notification({ method: CHANNEL_PERMISSION_REQUEST_METHOD, params }) } -
异步 Hook 执行
void (async () => { const hookDecision = await ctx.runHooks(...) if (hookDecision && claim()) { resolveOnce(hookDecision) } })() -
异步分类器执行
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>
决策流程:
-
模式检查
bypassPermissions: 直接允许plan: 计划模式规则auto: 分类器自动决策
-
规则匹配
alwaysAllowRules: 匹配则允许alwaysDenyRules: 匹配则拒绝
-
会话状态
- 非交互式会话可能有不同行为
-
分类器检查
- 仅 Bash 工具支持
- 异步执行
-
Hook 检查
- 执行 PermissionRequest hooks
-
降级到交互式
- 返回
{ 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 |
权限类型定义 |