Claude Code 权限系统中三类规则的匹配优先级(解析 deny、ask、allow 的求值顺序)

三类规则按 deny → ask → allow 的顺序求值,第一条命中的规则直接决定结果,且与规则的”具体程度”无关——一条宽泛的 deny 永远挡住一条精确的 allow,ask 也会盖过同样命中的 allow。这是 Claude Code 默认拒绝策略在工程上的直接体现,也是写权限配置时最容易踩的坑。

一、求值规则的一句话总结

官方文档原话:”Rules are evaluated in order: deny, then ask, then allow. The first match in that order determines the outcome, and rule specificity doesn’t change the order.” 这意味着:

  • 先扫所有 deny,命中即拒绝;
  • 未命中 deny 再扫 ask,命中即弹确认;
  • 未命中 deny 和 ask 最后扫 allow,命中即放行;
  • 三类都没命中时,默认升级为 ask(让用户决定)。

二、为什么具体程度不改变顺序

如果按”更具体的规则覆盖更宽泛的规则”这种直觉设计权限系统,配置会变得难维护且易误用。Claude Code 选择了”安全优先”的简单顺序:deny 永远是最先被检查的类别,ask 次之,allow 最后。这样写规则时只需关心”我要不要拦”,不用纠结”哪条更具体”。

配置示例:deny 不会被 allow 覆盖
permissions:
  allow:
    - "Bash(aws s3 ls)"
  deny:
    - "Bash(aws *)"

上面这个配置里,”aws s3 ls” 仍然会被 Bash(aws *) 拦下,不会因为它更具体就被放行。

三、deny 规则的两类行为

deny 规则根据写法有两种效果,必须分清:

写法 效果 适用场景
Bash(裸工具名) 把整个工具从模型上下文里删除 完全禁止某个工具类
Bash(rm *)(带括号限定) 工具仍可见,匹配的动作在调用时被拦 允许用 Bash 但禁止特定命令

裸 deny 适用”完全不该出现”的高风险工具(如 EndConversation 之外任意工具都可裸 deny);带 specifier 的 deny 适用”工具可用,但这条要拦”的精细控制。两者混用容易导致”以为挡住了,结果模型根本看不到工具”或反之。

四、ask 规则的边界

ask 规则是”总会弹确认”的兜底。三类容易混的点:

  1. ask 优先于 allow。即使用户已经配了 Bash(git commit *) 这种精确 allow,仍然可以为 Bash(git push *) 单独配一条 ask,每次推送都让人确认;
  2. ask 不会”自动记住”。和允许规则在弹窗里点”是,不要再问”的会话级持久化不同,ask 的目的是”任何时候都要人看一眼”;
  3. 未识别的工具默认按 ask 处理。模型提出一个没有匹配的调用,权限系统不会自作主张放行,而是弹给用户。

五、规则合并 vs 顺序的常见误解

误解一:”更具体的 allow 应该胜过更宽泛的 deny。”——不会,三类按顺序求值,deny 先吃。

误解二:”用 allow 写明细节就能逃开 deny。”——同样不会,因为顺序问题,deny 命中时根本没有 allow 机会。

误解三:”ask 配过就不会再弹。”——除非在弹窗里点”是,不要再问”且模式是按命令持久化的 allow,否则 ask 每次都弹。

误解四:”deny 写错只是放错一次。”——deny 写错可能让模型根本看不到工具(裸 deny)或被绕开(带 specifier 的 deny 没覆盖到位),错误形态更隐蔽。

六、可执行的规则排错步骤

  1. 跑 /permissions 命令,列出所有当前生效的规则及其来源(用户级 / 项目级 / 托管级);
  2. 找被错误拦截的调用,先看 deny 列表里有没有命中(最常见原因);
  3. 命中后判断是宽泛 deny 还是精确 deny:宽泛 deny 想要放行只能去掉这条;
  4. 没命中 deny 再看 ask 列表:ask 命中是无声的,弹窗容易让人误以为是 allow;
  5. 仍然没命中才会落到 allow;allow 不匹配时默认 ask,确认逻辑闭环。

七、规则来源与覆盖关系

优先级 来源 用途 典型设置
最高 托管设置(managed policy) 企业/组织统一下发 禁止删 ~/.ssh/、禁访问某些主机
中 项目级 .claude/settings.json 仓库内共享规则 禁止提交 .env、限制 Bash 命令
中 用户级 ~/.claude/settings.json 个人默认规则 允许常用 git 子命令
最低 会话内临时规则 临时调整 临时 deny 某危险命令

高优先级的设置会覆盖低优先级的同名规则。例如托管设置里 deny 了 Bash(rm -rf /),无论用户在项目或个人设置里怎么写 allow,都拦不下来。

八、配置实战

# .claude/settings.json
permissions:
  allow:
    - "Bash(npm run *)"
    - "Bash(git commit *)"
    - "Bash(* --version)"
  ask:
    - "Bash(git push *)"
    - "Bash(npm publish *)"
  deny:
    - "Bash(rm -rf /)"
    - "Bash(rm -rf ~)"
    - "Bash(* --force *)"
    - "Read(./.env)"
    - "WebFetch(domain:paste.example)"

按”先 deny 兜底、再 ask 显式确认、最后 allow 提速”三段式写权限,匹配顺序就完全可控,团队成员加新规则时也不容易撞到先前的硬约束。

常见问题(FAQ)

Q1:更具体的 allow 能不能盖过宽泛的 deny?

不能。三类规则按 deny→ask→allow 顺序求值,deny 命中就拦截,与具体程度无关。

Q2:ask 和 allow 都命中时听谁的?

听 ask 的。ask 的优先级高于 allow,会强制弹确认。

Q3:deny 写错会让工具消失吗?

会的,裸 deny(如 Bash)会把整个工具从模型上下文里抹掉,模型甚至看不到它。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 qiqicto@qq.com 举报,一经查实,本站将立刻删除。
赞 (0)
命令行手艺人的头像命令行手艺人普通用户

相关推荐

返回顶部