Skip to content

05. 权限模型入门

权限是工程纪律的第一道防线。它不是"确认弹窗"那么简单——它是你把 Claude Code 从问答工具升级为可验证工程代理时,唯一能在自动化与安全之间画线的机制。

这一章给结论:权限模型由三层构成,缺一不可。

  1. 规则数组——allow / deny / ask,声明哪些工具调用自动放行、哪些拒绝、哪些询问。
  2. 配置文件层级——managed / user / project / local 四级,优先级从高到低,决定规则在哪里生效、谁能覆盖谁。
  3. 权限模式——default / acceptEdits / plan / bypassPermissions / auto / dontAsk 六种,控制"询问还是不询问"的整体策略。

核心原则一句话:让低风险命令自动跑、高风险动作必定停。配置得好,Claude 能在测试-修改-再测试的闭环里高速循环而不打断你;配置得不好,要么每条命令都弹窗把人逼疯,要么 bypassPermissions 一开,把仓库和生产环境一起送走。

本章按这三层展开,最后给出一份可直接落地的 settings.json 与一套红线清单。版本基准:2026-07-08,Claude Code v2.1.202+。

5.1 规则数组:allow / deny / ask 的语义与语法

5.1.1 三种语义

permissions 下的三个数组定义了工具调用的处置策略:

数组语义典型用途
allow自动放行,不询问只读操作、测试、Lint、类型检查
ask弹窗询问,等待人工决策git commit、外部 curl、有副作用但非破坏性
deny直接拒绝,不询问也不可被下层覆盖读凭据、git pushrm -rfnpm publish

求值顺序固定为 deny → ask → allow。任何工具调用先过 deny 检查,命中即拒,不会被 allow 覆盖。这条顺序保证了"危险动作无论在哪个层级被允许,都能被更高层级的 deny 拦下"——这是 deny 作为兜底红线的工程含义。

5.1.2 规则语法

规则由工具名 + 括号参数组成,参数支持 gitignore 风格的通配:

json
{
  "permissions": {
    "allow": [
      "Read",
      "Glob",
      "Grep",
      "Bash(npm test)",
      "Bash(npm test *)",
      "Bash(git diff*)",
      "WebFetch(domain:example.com)"
    ],
    "ask": [
      "Bash(git add *)",
      "Bash(git commit *)",
      "Bash(curl *)"
    ],
    "deny": [
      "Read(.env)",
      "Read(.env.*)",
      "Read(secrets/**)",
      "Bash(git push *)",
      "Bash(git reset --hard *)",
      "Bash(rm -rf *)",
      "Bash(npm publish *)"
    ]
  }
}

四个高频踩坑点(官方文档明确):

  1. 前缀通配必须用空格:Bash(npm test *) 匹配 npm test auth.spec;而 Bash(npm test*)(无空格)会连带匹配 npm testcoverage 这类无关命令。空格分隔的是"命令"与"参数"。
  2. 冒号写法是错的:Bash(npm test:*) 不工作。冒号只用于参数级匹配,如 WebFetch(domain:example.com)Agent(isolation:worktree),不用于命令前缀。
  3. 文件类规则遵循 gitignore 语义:Read(.env)Read(**/.env) 等价,匹配任意层级的 .env;要匹配仓库任意位置用绝对路径形式 Read(//**/.env)
  4. Read / Edit 规则不能替代操作系统级沙箱。脚本可以通过 catcurl 间接读取文件,权限规则只管 Claude 直接调用的工具。要做强隔离,启用 Claude Code sandbox,并把秘密放在工作目录之外。

交互式查看当前生效规则:

text
/permissions

5.2 配置文件层级:managed / user / project / local

5.2.1 四级优先级

规则不是写在一个文件里,而是分散在四个层级,优先级从高到低:

层级文件位置谁来维护是否提交 Git典型用途
managed policy企业下发(平台级)IT / 安全团队不可被用户覆盖企业强制红线
user~/.claude/settings.json个人不提交(在 home)跨项目个人偏好
project.claude/settings.json团队提交,团队共享项目级规范、团队红线
local.claude/settings.local.json个人不提交(加 .gitignore)个人临时偏好、实验性放行

优先级含义:managed 的规则不可被下层覆盖;user、project、local 之间,高优先级的 deny 可以压过低优先级的 allow,反之不行。这条机制保证了"团队的 deny 不会被个人的 allow 绕过"——也是为什么企业场景下 managed policy 能成为合规底线。

一个容易忽略的细节:四层只对"规则数组"叠加求值,不对"权限模式"叠加。权限模式取当前会话生效的那一个(通常由启动 flag 或 Shift+Tab 指定),不存在"managed 模式覆盖 user 模式"的说法。这也意味着:managed policy 锁死的是"哪些动作永远不能被允许",而不是"当前用哪种询问策略"。

5.2.2 managed policy 的企业场景

managed policy 在个人开发里很少见,但在企业、受监管行业里是合规底线。典型场景:

  • 金融机构合规要求:任何代码不得读取生产数据库凭据,任何 git push 不得绕过 PR 审查。IT 团队把 Read(**/prod-credentials/**)Bash(git push *) 写进 managed policy,开发者无法在本地 settings.json 里用 allow 覆盖。
  • 受监管代码库:法律要求所有变更可追溯,Bash(git commit --amend *)Bash(git rebase *) 进 managed deny,保证 Git 历史不可篡改。

个人开发者用不到 managed policy,但理解它的存在有助于建立"权限是分层合规体系"的认知:权限不只是你个人的效率工具,也是组织级的安全边界。本书第六部分讲一人公司产品化时,会回到这个概念——当你为客户交付项目,你自己的 settings.json 就是客户资产的 managed policy。

5.2.3 project vs local:该放什么

这是新人最容易混淆的判断。判断标准只有一条:这条规则对团队里每个人都要生效吗?

  • 是 → project(.claude/settings.json,提交 Git)。例如:本项目禁止 npm publish、禁止读 secrets/、测试命令是 npm test、Lint 命令是 npm run lint。这些是项目级共识,新人 clone 下来就有保护。
  • 否 → local(.claude/settings.local.json,不提交)。例如:你个人临时允许 Bash(docker compose up *) 做本地联调,但同事用 Podman 不需要;你个人偏好自动接受某个实验性脚本。这些放 local,不要污染团队配置。

一个常见反例:把个人偏好的 Bash(pnpm *) 写进 project 的 settings.json,结果团队里用 npm 的同事也被强行套上 pnpm 规则。项目配置只放共识,个人偏好回 local

.claude/settings.local.json 应当在 .gitignore 里显式忽略,避免误提交:

text
.claude/settings.local.json

5.3 权限模式:六种策略

规则数组定义了"哪些动作放行/拒绝/询问",权限模式定义了"整体上问还是不问"。两者叠加,决定了 Claude 的实际行为。

5.3.1 六种模式

模式行为适用场景风险
default(Manual)每个有副作用的工具调用都弹窗询问新项目、陌生仓库、首次探索低,但打断频繁
acceptEdits自动接受工作区内文件编辑,其他命令仍询问信任范围内的代码修改中,误编辑不会被拦
plan只读分析,禁止任何文件改动与有副作用命令方案设计、影响评估、代码审查极低
bypassPermissions取消全部控制面,等价 --dangerously-skip-permissions极少推荐;一次性沙箱实验极高,见 5.6
auto(新,research preview)后台分类器自动审核,约 93% 提示被批准,高风险动作仍拦截熟悉项目后的日常开发中,残余 7% 风险
dontAsk未显式允许的工具自动拒绝(不弹窗),allow 列表仍可用CI、headless、非交互脚本低,但会拒绝部分有用工具

auto 模式标注为 research preview(2026-07-08 核对)。它的"93% 批准率"是官方公布的统计值,意味着大约每 14 次工具调用有 1 次仍会弹窗或拒绝。不能把它当 bypassPermissions 用。

5.3.2 切换方式

两种切换路径:

交互式(会话内):Shift+Tab 在六种模式间循环切换,状态栏显示当前模式。适合开发中根据任务阶段动态调整——读代码时切 plan,动手改时切 acceptEdits,跑完整流程时切 auto

启动时指定(命令行 flag):

bash
claude --permission-mode plan
claude --permission-mode acceptEdits
claude --permission-mode auto

适合脚本化场景。CI 里跑 headless 审查,固定用 plandontAsk:

bash
claude -p --permission-mode dontAsk \
  --max-turns 10 \
  "审查当前 git diff,只报告高置信度问题,不修改文件"

dontAsk 在这里的妙处:未显式允许的工具调用不会被弹窗卡住(脚本环境无法响应弹窗),而是直接拒绝,让 Claude 知道这条路不通,转而走 allow 列表里的只读工具。这是 headless 场景下既安全又不卡死的正确姿势。

5.3.3 规则与模式如何叠加

这是新人最困惑的问题:allow 里的命令在 default 模式下还会问吗?在 dontAsk 下呢?答案是按"模式先判断,规则再兜底"的顺序求值。

具体叠加矩阵:

模式 \ 规则命中denyaskallow未匹配任何规则
default拒绝询问放行询问
acceptEdits拒绝询问放行文件编辑放行,其他询问
plan拒绝拒绝拒绝(有副作用者)拒绝
auto拒绝分类器判断放行分类器判断
dontAsk拒绝拒绝放行拒绝
bypassPermissions仍拒绝放行放行放行

两个关键结论:

  1. deny 在任何模式下都生效,包括 bypassPermissions。这是为什么 deny 是兜底红线——即使你疯了开 bypassPermissions,Bash(rm -rf *) 仍然会被拦。但要注意:bypassPermissions 之所以危险,是因为它放行了所有"未匹配规则"的动作,而你的 deny 列表不可能穷举所有危险命令。
  2. plan 模式比 default 更严格plan 下连 allow 里的有副作用命令也会被拒——因为它要保证"只读分析"的语义。plan 是唯一一个"allow 不总生效"的模式。

理解了这张矩阵,你就能预判任何配置下的实际行为,不用反复试错。

5.4 一份可直接落地的 settings.json

下面是 project 级 .claude/settings.json 的完整可用模板,覆盖一个典型 Node.js 项目的日常开发。复制即用,按需调整命令名(Python 项目换成 Bash(pytest *)、Go 项目换成 Bash(go test *))。

json
{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "permissions": {
    "allow": [
      "Read",
      "Glob",
      "Grep",
      "Bash(npm test)",
      "Bash(npm test *)",
      "Bash(npm run test)",
      "Bash(npm run test *)",
      "Bash(npm run lint)",
      "Bash(npm run lint *)",
      "Bash(npm run typecheck)",
      "Bash(npm run typecheck *)",
      "Bash(npm run build)",
      "Bash(git status)",
      "Bash(git status *)",
      "Bash(git diff)",
      "Bash(git diff *)",
      "Bash(git log)",
      "Bash(git log *)",
      "Bash(git branch)",
      "Bash(git branch *)"
    ],
    "ask": [
      "Bash(git add *)",
      "Bash(git commit *)",
      "Bash(curl *)",
      "Bash(docker *)",
      "Bash(make *)"
    ],
    "deny": [
      "Read(.env)",
      "Read(.env.*)",
      "Read(secrets/**)",
      "Read(**/credentials.json)",
      "Read(**/*.pem)",
      "Bash(git push *)",
      "Bash(git push -f *)",
      "Bash(git push --force *)",
      "Bash(git reset --hard *)",
      "Bash(git rebase *)",
      "Bash(git checkout -- *)",
      "Bash(rm -rf *)",
      "Bash(rm -rf /)",
      "Bash(sudo *)",
      "Bash(npm publish *)",
      "Bash(npx publish *)",
      "Bash(pnpm publish *)"
    ]
  }
}

这套配置的意图,按动作分类:

动作策略原因
读源码、搜索符号、git 只读命令allow低风险且高频,放行以构成自动闭环
跑测试、Lint、类型检查、构建allow构成"改-测-改"自动修正闭环
git add / git commit / curl / dockerask有持久或外部副作用,但非破坏性,人工确认
读凭据、推送、重写历史、删除、发布deny不应由项目级配置放行

注意 deny 里的 Bash(sudo *)——任何提权操作都应被拦下,因为 sudo 一旦执行,后续命令绕过的是操作系统权限,Claude 的权限规则不再有效。sudo 是权限模型的逃生舱,必须锁死。

5.5 分层授权原则:读 / 写 / 破坏性

权限配置的本质是按"动作风险"分层。三层原则:

第一层:读操作全部自动允许。

ReadGlobGrepgit statusgit diffgit log——这些不产生任何副作用,Claude 越多读越准,拦下它们只会拖慢闭环、逼 Claude 凭记忆猜。唯一例外:凭据文件(.envsecrets/*.pem),这些进 deny,不是因为读本身危险,而是读进上下文后续可能被写进 commit 或日志。

第二层:写操作按项目约定放开。

EditWrite 是否自动允许,取决于项目成熟度。新项目、个人项目:用 acceptEditsauto 模式,自动接受编辑。遗留项目、生产代码:用 default 模式,每个编辑都确认。测试与 Lint 命令(npm testnpm run lint)属于"写但低风险",放 allow——它们是闭环的一部分,拦下它们就等于不让 Claude 自我验证。

第三层:破坏性操作永远不自动允许。

删除、推送、重写历史、发布、数据库变更、提权——这些动作的失败成本不可逆。无论项目多成熟、模式多激进,它们都必须进 deny 或至少 ask。理由不是"不信任 Claude",而是"不信任任何自动化对不可逆动作的判断"。一次 rm -rf 的代价,远高于一辈子为它按 n 的成本。

5.6 安全红线意识:六类必须二次确认

借鉴一位资深用户的 CLAUDE.md 红线边界理念(本教程作者也采用),以下六类操作即使在 auto-accept 模式下也必须绝对中止并二次确认:

  1. 破坏性修改:删除文件、删除目录、篡改 Git 历史(git rebasegit reset --hardgit push --force)。
  2. 凭据安全:修改 .env 文件、密钥、Token 或 CI/CD 配置。严禁密钥进入代码、commit 或日志。
  3. 数据安全:执行数据库 Schema 变更或数据迁移(DROP TABLEALTER TABLEDELETE FROM 不带 WHERE)。
  4. 风险命令:git pushgit rebasegit reset --hard、强制推送。
  5. 环境污染:安装新的全局依赖(npm install -g)、修改系统级配置。
  6. 公开发布:npm publish、部署到生产环境、发布文章。

这六类的共同特征:动作外部化、影响不可逆、超出当前仓库边界。Claude Code 的权限模型管的是"工作区内工具调用",但 git push 把变更送到了远端、npm publish 把包送到了公共注册表、生产部署把代码送到了线上——这些动作的后果已经超出权限模型能回收的范围。

settings.json 里,这六类全部进 deny。在 CLAUDE.md 里,用自然语言再强调一次,让 Claude 在调用工具前主动核对。规则变更顺序:先改文档,再改代码实践,严禁倒置。

一个补充:bypassPermissions(即 --dangerously-skip-permissions)不在日常推荐之列。它取消的是人类控制面,不是模型犯错的可能性。Claude 在 bypassPermissions 下仍然会幻觉、会误删、会推错分支——只是没人拦它。唯一可接受的场景是一次性、可丢弃的沙箱实验,且工作区内没有任何敏感文件、不挂载任何凭据。把它当日常捷径,迟早翻车。

5.6.1 在 CLAUDE.md 里用自然语言强化红线

settings.jsondeny 是机器可执行的硬规则,但 Claude 在调用工具前也会读 CLAUDE.md。两层防线互相补充:deny 拦下已知的危险命令,自然语言红线拦下"deny 列表没穷举到"的边缘动作。

CLAUDE.md 里加一段:

markdown
## 红线边界(Autonomous Boundaries)
注意:以下操作即使在 auto-accept 模式下,也必须绝对中止并向我二次确认!
1. 破坏性修改:删除文件、目录或篡改 Git 历史。
2. 凭据安全:修改 .env 文件、密钥、Token 或 CI/CD 配置(严禁密钥进入代码、commit 或日志)。
3. 数据安全:执行数据库 Schema 变更或数据迁移。
4. 风险命令:执行 git push、git rebase、git reset --hard 或强制推送。
5. 环境污染:安装新的全局依赖或修改系统级配置。
6. 公开发布:执行 npm publish、部署到生产环境或发布文章。

这段自然语言的作用,是让 Claude 在"工具调用前的推理阶段"就主动核对:它要执行的下一个动作是否触及这六类。如果触及,它应当先停下来询问,而不是执行后等你拦。deny 是事后硬拦截,CLAUDE.md 红线是事前软拦截——两层叠加,才构成完整的工程纪律。

规则变更顺序:先改 CLAUDE.md,再改 settings.json 实践,严禁倒置。先有共识,再有执行。

5.7 失败边界:过宽、过烦、auto 的残余风险

权限配置的三种典型失败模式:

失败一:过宽——bypassPermissions 误用。

症状:Claude 跑得很顺,直到某天它自信地删掉了关键文件、推到了 main 分支、或者把测试日志里的 secret push 到了远端。

根因:把"不打断"当成目标,忽略了"打断"是唯一的安全阀。bypassPermissions 不是效率工具,是紧急逃生通道——平时不用,用了就要承担全部后果。

补救:立即退出该会话,用 git reflog 恢复历史,检查 git log -p 找回被删文件。长期解药:删除 bypassPermissions 的所有使用,改用 autoacceptEdits + 精心维护的 deny 列表。

失败二:过烦——每条命令都弹窗。

症状:开发一小时,按了 40 次 y,注意力被切碎,开始无脑按 y——这是最危险的状态,比 bypassPermissions 还危险,因为人已经丧失了判断力。

根因:allow 列表太空,或者用了 default 模式跑长闭环。

补救:用 /permissions 查看当前规则,把高频低风险命令补进 allow。本书附录会介绍 /fewer-permission-prompts 自定义 skill,它能扫描会话历史里频繁出现的只读命令,生成 allowlist 候选。短期解法:跑长闭环前切 acceptEditsauto

失败三:auto mode 的 93% 批准率与残余风险。

症状:用 auto 模式,大部分时候顺畅,偶尔 Claude 调用某个边界工具被拦截,任务卡住。

根因:auto 的后台分类器基于风险预测,不是规则匹配。93% 批准率意味着 7% 的工具调用仍会被拦——这 7% 里既有真正危险的动作(好事),也有误判的安全操作(烦事)。

补救:把误判频繁的安全命令显式加进 allow(显式 allow 优先于 auto 的分类器判断)。不要因为 auto 偶尔拦就把这些命令移到 deny 之外做特殊处理——保持 deny 干净,只放真正的红线。

auto mode 是 research preview,行为可能随版本变化。生产关键路径上不要完全依赖它,保留人工 review 作为最后一道关。

5.8 小结

权限模型三层,记住一张图:

text
规则数组(allow/deny/ask)        —— 静态声明:哪些工具调用放行/拒绝/询问
        +
配置层级(managed/user/project/local) —— 动态生效:规则在哪里、谁能覆盖谁
        +
权限模式(六种)                  —— 整体策略:问还是不问
        =
Claude 的实际行为

落地三条:

  1. project 配置放共识,local 配置放个人。项目级 .claude/settings.json 提交 Git,个人偏好回 .claude/settings.local.json
  2. 读操作放行,写操作按项目定,破坏性永远 deny。这是分层授权的核心。
  3. 六类红线不自动。破坏性修改、凭据、数据、风险命令、环境污染、公开发布——即使 auto-accept 也必须二次确认。

下一章进入工程篇,讲 Claude Code 的核心心智模型与命令真实性——为什么"工具调用是事实来源,记忆不是",以及如何识破 Claude 的幻觉。


上一章:第 4 章 CLAUDE.md 与上下文入门
下一章:第 6 章 核心心智模型与命令真实性