Skip to content

细粒度权限

第三章讲了四种权限模式,是宏观开关。这一节讲开关的下一层:具体到某个工具、某条命令、某个路径、某个域名。写好细粒度规则之后,你的 Claude Code 能自动放行 git status,但仍然会拦下 git push --force

为什么要细化

default 模式下 Claude 每动一次工具都要问你,很烦。bypassPermissions 又太放任,一个 rm 错了没人拦。真正实用的是介于两者之间的做法:把"肯定安全"的事情写进 allow list 自动放行,把"肯定危险"的事情写进 deny list 直接拒绝,剩下的模糊地带才走人工审批。这样每天需要人干预的次数会从几十次掉到个位数。

Claude Code 的权限规则支持四种粒度,从粗到细依次是工具、命令、路径、域名。你完全可以在一个 settings.json 里混用。

工具粒度

最粗的一层,直接按工具名放行或拒绝。

json
{
  "permissions": {
    "allow": [
      "Read(**)",
      "Grep(**)",
      "Glob(**)"
    ]
  }
}

上面这段的意思是 Read、Grep、Glob 三种只读工具在任何路径都自动放行。这三类是读操作,风险接近零,放开之后 Claude 探索项目会顺畅很多,不必每次读一个文件都问你。

如果你想让 Edit 也自动放行,那就用 Edit(**)。括号里的部分是路径 pattern,** 表示任意路径。

路径粒度

只让 Claude 自动编辑某些目录,其他目录仍然需要问。

json
{
  "permissions": {
    "allow": [
      "Edit(src/**)",
      "Edit(tests/**)",
      "Write(scratch/**)"
    ]
  }
}

src/** 匹配 src 目录下任意深度的文件,包括 src/index.ts 也包括 src/routes/users/handler.ts。Write 只让写到 scratch/**,是因为草稿目录反正会被 gitignore,写坏了没事,但根目录下的关键文件必须走审批。

路径 pattern 遵循标准 glob 语法:* 单层通配、** 任意层通配、? 单字符通配,可以在同一条规则里组合使用。

命令粒度

Bash 是最容易出事的工具,也是最需要细化的一类。命令粒度的规则用 Bash(<prefix>:*) 语法。

json
{
  "permissions": {
    "allow": [
      "Bash(git status:*)",
      "Bash(git diff:*)",
      "Bash(git log:*)",
      "Bash(git branch:*)",
      "Bash(npm test:*)",
      "Bash(pnpm test:*)",
      "Bash(pnpm exec tsc --noEmit:*)"
    ],
    "deny": [
      "Bash(git push --force:*)",
      "Bash(git push -f:*)",
      "Bash(git reset --hard:*)",
      "Bash(rm -rf:*)"
    ]
  }
}

冒号加星号是必须的,表示这条规则匹配以该前缀开头的所有 Bash 命令。Bash(git status:*) 会放行 git statusgit status --shortgit status -uno 等所有变体,但不会放行 git statusfoo(因为要求以完整词组作为前缀)。

deny 优先级高于 allow。哪怕你写了 Bash(git push:*) 放行 push,只要 deny 列表里有 Bash(git push --force:*),force push 依然会被拒绝。团队共享的 settings 里,deny 列表是最重要的资产,写得越具体越安全。

域名粒度

WebFetch 工具用得多的团队还要控制外网访问。

json
{
  "permissions": {
    "allow": [
      "WebFetch(https://docs.claude.com/**)",
      "WebFetch(https://github.com/**)",
      "WebFetch(https://*.mycompany.internal/**)"
    ],
    "deny": [
      "WebFetch(http://**)"
    ]
  }
}

这段配置放行了官方文档、GitHub、公司内网所有子域名,同时拒绝一切明文 HTTP。域名 pattern 里的 * 只匹配单一子域段,** 匹配路径任意深度。

additionalDirectories

Claude Code 默认只能访问工作目录及其子目录。有时候你需要它读工作目录以外的文件,比如另一个仓库的 schema、或者一份放在家目录下的私有配置。

json
{
  "permissions": {
    "additionalDirectories": [
      "../shared-schema",
      "~/.config/mytool"
    ]
  }
}

配置之后 Claude 能读这些目录的文件,允许列表里那些 Read、Edit 规则也会作用到它们。这个字段是"让工作目录变大",不是"绕过权限",具体的 allow/deny 规则依然要写。

别把家目录整个加进来

additionalDirectories 加一整个 ~ 意味着 Claude 能看到你所有的私人文件。加你真的需要的具体子目录,别偷懒。

Deny 列表:把敏感文件锁死

有些文件即使在 allow 模式下也绝对不能碰。敏感文件的显式 deny 是防御的最后一道墙。

json
{
  "permissions": {
    "deny": [
      "Read(.env)",
      "Read(.env.*)",
      "Read(**/credentials.json)",
      "Read(**/secrets/**)",
      "Read(**/*.pem)",
      "Read(**/*.key)",
      "Edit(.env)",
      "Edit(.env.*)"
    ]
  }
}

Read 拒绝之后 Claude 连内容都看不到,不会出现在上下文里,不会被误发到聊天记录里。Edit 拒绝防止 Claude 误改凭证文件。哪怕未来某天你手滑开了 bypassPermissions,deny 依然会挡住这些路径。

MCP 工具权限

第六章会详细讲 MCP。这里先说权限层怎么写。MCP 提供的工具名格式是 mcp__<server-name>__<tool-name>,写规则时用同样的完整名字。

json
{
  "permissions": {
    "allow": [
      "mcp__lark-doc__read_docx",
      "mcp__lark-sheets__read_range"
    ],
    "deny": [
      "mcp__lark-doc__delete_docx",
      "mcp__lark-drive__delete_file"
    ]
  }
}

只读的 MCP 工具通常都可以放行,写和删这类破坏性操作留给审批。命名规范里 __ 是双下划线,容易看错,配置时复制粘贴不要手打。

完整示例:团队共享 settings.json

把上面全部粒度串起来,一份可以直接进 git 的团队配置长这样。

json
{
  "permissions": {
    "additionalDirectories": [
      "../shared-schema"
    ],
    "allow": [
      "Read(**)",
      "Grep(**)",
      "Glob(**)",
      "Edit(src/**)",
      "Edit(tests/**)",
      "Write(scratch/**)",
      "Bash(git status:*)",
      "Bash(git diff:*)",
      "Bash(git log:*)",
      "Bash(git branch:*)",
      "Bash(pnpm test:*)",
      "Bash(pnpm exec tsc --noEmit:*)",
      "Bash(pnpm exec prettier --write:*)",
      "WebFetch(https://docs.claude.com/**)",
      "WebFetch(https://github.com/**)",
      "mcp__lark-doc__read_docx"
    ],
    "deny": [
      "Read(.env)",
      "Read(.env.*)",
      "Read(**/credentials.json)",
      "Read(**/secrets/**)",
      "Read(**/*.pem)",
      "Edit(.env)",
      "Edit(.env.*)",
      "Bash(git push --force:*)",
      "Bash(git push -f:*)",
      "Bash(git reset --hard:*)",
      "Bash(rm -rf:*)",
      "WebFetch(http://**)",
      "mcp__lark-doc__delete_docx"
    ]
  }
}

这份 settings.json 放到 ./.claude/settings.json 提交到仓库,团队里任何人 clone 之后开 Claude Code 都是同一套规则。个人偏好放到 ./.claude/settings.local.json(gitignore 掉),互不干扰。

从紧到松,一次只加一条

不建议一上来就把所有 allow 一口气都开。先从 Read、Grep、Glob 开起,跑一周看看哪几类 Bash 命令你每天都在按同意,把那几条加进 allow。这样加出来的规则贴近你真实的使用习惯,也不容易漏掉重要的 deny。

deny 是防线,不是唯一防线

bypassPermissions 模式会绕过 allow 但仍然遵守 deny。不过 deny 只挡了显式列出的路径,能列的都是你已经想到的。真正的安全依赖多层组合:deny 列表挡已知敏感文件,Hooks 拦已知危险命令,人工审批处理未知情况,三者缺一不可。

本教程为社区中文学习整理,非官方发布。Claude Code 属于 Anthropic。