Files
claude-code-mirror/claude-code-中文Wiki/07-权限系统.md
2026-04-03 13:01:19 +08:00

656 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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<string, unknown>,
toolUseContext: ToolUseContext,
assistantMessage: AssistantMessage,
toolUseID: string,
setToolPermissionContext: (context: ToolPermissionContext) => void,
queueOps?: PermissionQueueOps,
)
```
### 上下文方法
```typescript
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`
### 决策类型
```typescript
type PermissionDecision =
| { behavior: 'allow'; updatedInput?: Record<string, unknown>; ... }
| { 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<string, unknown>
command: string
// ...
}
```
---
## 4. 权限处理器
### 4.1 Coordinator Handler
**文件位置**: `src/hooks/toolPermission/handlers/coordinatorHandler.ts`
用于协调者工作进程coordinator worker的权限处理流程。
```typescript
async function handleCoordinatorPermission(
params: CoordinatorPermissionParams
): Promise<PermissionDecision | null>
```
**处理流程**:
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<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
}
```
### 权限响应
```typescript
type BridgePermissionResponse = {
behavior: 'allow' | 'deny'
updatedInput?: Record<string, unknown>
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<string, unknown>
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<ClassifierDecision | null>
```
---
## 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<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
```typescript
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. 关键常量
```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` | 权限类型定义 |