教程2026-10-26 · 智涌AI

Claude Code 权限配置详解:settings.json 的 allow/deny 实测 28 次

Claude Code 权限配置头图:终端里 deny 规则拦住 rm 和 cat .env,但 find -delete 与 python 读取照样执行

Claude Code 每次要跑命令、改文件都弹窗问你,点多了就想一键全放行;全放行又怕它哪天 rm 掉不该删的东西。折中的办法是 settings.json 里的 permissions:哪些命令直接放、哪些必须问、哪些一律拒绝。我们在本机用 Claude Code 2.1.309 跑了 28 次工具调用,把文档里最容易误解的几条规则逐条试了一遍。

前置条件

四个文件各管一摊,列表会合并

装完 Claude Code 不会自带设置文件,下面四个按需自己建:

文件影响谁适合放什么
~/.claude/settings.json你,本机所有项目个人习惯、自己的通用权限
.claude/settings.json这个项目的所有人(提交进 git)团队统一的权限、钩子、插件
.claude/settings.local.json你,只在这个项目个人例外;弹窗里点「Yes, and don't ask again」也写这里
托管设置(managed-settings.json 等)组织下发到的所有人安全策略,别的层改不了

同一个键写在多处时,优先级从高到低是:托管设置 → 命令行 --settings → 项目本地 → 项目共享 → 用户级。permissions.allow 这种列表不按优先级覆盖,而是几个文件的条目合在一起。改完在会话里输 /status,「Setting sources」一行会列出这次加载了哪些文件;/permissions 能看到每条规则来自哪个文件。

规则怎么写:deny 先于 ask,ask 先于 allow

一个够用的起步配置:

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "permissions": {
    "allow": ["Bash(npm run *)", "Bash(git commit *)", "Bash(git log *)"],
    "ask":   ["Bash(git push *)"],
    "deny":  ["Read(./.env)", "Read(./.env.*)", "Read(./secrets/**)", "Bash(curl *)"]
  }
}

判定顺序是固定的:先看 deny,再看 ask,最后看 allow,命中谁算谁,跟哪条写得更具体无关。所以 deny 了 Bash(aws *),再 allow Bash(aws s3 ls) 也开不了口子。几条写法上的细节:

在 CLAUDE.md 里写「不要读 .env」,模型可以不照做;写进 permissions.deny,Read 工具和 cat 就都读不到了。下面会看到,换一种读法照样能读出来。

实测一:项目里的 allow 规则,可能根本没生效

同一条 "allow": ["Bash(rm *)"],同一条 rm build/out.txt,分别放进三个文件:

终端:同一条 allow 规则放在项目共享文件时被忽略并拒绝,放在本地文件和用户级文件时命令执行
2026-10-26 本机 Claude Code 2.1.309:项目共享文件里的 allow 在未信任的文件夹被忽略,stderr 给出原因。

放在 .claude/settings.json 时,stderr 打出 Ignoring 1 permissions.allow entry from .claude/settings.json: this workspace has not been trusted,命令被拒,文件还在。放进没被 git 跟踪的 settings.local.json 或用户级文件,命令直接执行。把这个目录在配置里标成已信任(hasTrustDialogAccepted: true)之后,项目文件里的规则才生效。

官方的解释是:allow 规则是在给权限,所以项目文件里的 allow 要等你在交互界面接受「信任此文件夹」后才算数;claude -p 和 SDK 从不弹这个对话框。deny 和 ask 只会收紧,不受信任限制。在 CI 里跑 claude -p,又指望仓库里的 allow 放行命令,命令会全部被拒,原因只打在 stderr 里,很容易漏看。

实测二:deny 能拦住什么,拦不住什么

终端:deny Bash(rm *) 拦住 rm、timeout rm、/bin/rm、bash -c,没拦住 find -delete 和 python;deny Read(.env) 拦住 Read 和 cat,没拦住 python 和 grep -r
同一台机器同一版本,红色是被拒,绿色是照样执行了。
设置命令结果
allow Bash(git *) + deny Bash(git push *)git push origin main拒绝
git -C . push origin main执行了(只是没有远端,git 自己报错)
allow Bash + deny Bash(rm *)timeout 5 rm …、FOO=1 rm …拒绝
/bin/rm …、bash -c "rm …"拒绝
find build -name out.txt -delete执行,文件被删
python3 -c "import os; os.remove(…)"执行,文件被删
allow Bash(python3 *) + deny Read(./.env)Read 工具读 .env、cat .env拒绝
python3 -c "print(open('.env').read())"、grep -r SECRET .执行,输出了 SECRET=abc123

官方文档的例子表里,/bin/rm 和 bash -c 属于 deny 规则「不保证拦住」的写法,我们这个版本实测拦住了,但别指望它。文档的原话是:Bash 规则只匹配命令文本,不是围着程序的安全边界。find -delete、Python 脚本、git -C 这些换个写法的调用都能绕过去。

想要硬边界有两条路:一是开沙箱,在操作系统层限制 Bash 的文件和网络访问;二是用 PreToolUse 钩子自己检查完整命令,写法见站内的 Claude Code Hooks 实战。

实测三:几个跟直觉不一样的地方

常见坑

  1. 团队仓库里的 allow 没生效。先看 stderr 有没有「has not been trusted」。交互模式下接受一次信任对话框;CI 里用 --settings 传一份你自己控制的配置,别靠仓库文件放行。
  2. 以为 deny 了 .env 就安全了。同时 allow 了 Bash(python3 *) 或 Bash 时,脚本照样能读。敏感文件要配沙箱的文件系统限制,或者干脆别放在 Agent 的工作目录里。
  3. JSON 写错,整个文件失效。设置文件是严格 JSON,不能写 // 注释和结尾逗号。交互启动时会弹 Settings Error;单条规则写错只出 Settings Warning,跳过那条。拿不准就跑 claude doctor。
  4. bypassPermissions 被人顺手打开。在托管设置或你自己的用户设置里加 "disableBypassPermissionsMode": "disable",这个模式就开不了。

完成标准

想先补概念,可以看 Claude Code 上手篇;接 MCP 工具时规则写法是 mcp__服务器名__*,见 MCP Tasks 实测。

最后

今天就在 ~/.claude/settings.json 里加三条 deny:Read(./.env)、Read(./.env.*)、Bash(git push *),然后用 /permissions 确认它们已经生效。

关注公众号「智涌AI速递」

每天的 AI 快讯、实用教程和 AI项目实测,也会同步发到微信公众号。在微信里搜索「智涌AI速递」就能关注;不用微信的话,可以用 RSS 订阅本站。