首页 › tutorials › 给首个项目装权限围栏

概述

本教程面向首次把 Claude Code 引入真实代码仓库的零基础开发者。学完之后,你将能够:理解 Claude Code 的三层权限模型(模式 + 规则 + 钩子),读懂并写出 allow/deny/ask 规则,为你的第一个项目配置一份"只放行本地构建、禁止推送与外发网络"的安全围栏,并掌握在多档权限模式之间自如切换的方法。适用人群:刚完成安装、能跑通 claude 命令,但还没敢把它指向自己项目根目录的开发者。

前置条件

如果你还没装好,先回去完成安装与登录再回来——本教程不重复安装步骤,专注配置这一最容易踩坑、也最该在"第一个项目"阶段就做对的环节。

正文

步骤 1:先建立心智模型——三层权限体系

很多初学者一上来就问"我该把哪个开关关掉",结果越改越乱。先记住一张三层图:

  1. 权限模式(mode):决定"基线"。当前模式下哪些动作默认免提示。
  2. 权限规则(rules):在基线之上叠加"白名单/黑名单/必问清单"。
  3. 钩子(hooks):在工具调用前后注入脚本,做最细粒度的拦截与审计。

这三层由 Claude Code 强制执行,不是由模型自觉。你在 CLAUDE.md 里写"请不要删文件"没有任何约束力,真正起作用的是 deny 规则和 PreToolUse 钩子。理解这一点,后面的配置才不会南辕北辙。

步骤 2:认识六种权限模式,知道每档"放行"到哪

模式决定了"Claude 不问你就能做的事"边界。这是你给项目选基线的第一道选择题:

模式 免提示可做的事 适用场景
default 仅只读操作(读文件、grep) 入门、敏感操作
acceptEdits 只读 + 文件编辑 + 常见文件系统命令(mkdir/touch/mv/cp) 你正盯着看的代码迭代
plan 仅只读(只读探查,不改源码) 动手前先摸清仓库
auto 几乎全部,带后台安全校验(研究预览) 长任务、减少审批疲劳
dontAsk 仅预先批准过的工具 锁定的 CI 与脚本
bypassPermissions 全部 仅限隔离容器/虚拟机

一条贯穿所有模式的安全底线:除了 bypassPermissions,对"受保护路径"(.git、.claude、.config/git、.vscode、.idea、.husky 等)的写入永远不会被自动批准。这条底线是为了防止 Claude 误改自己的配置或仓库状态。而 deny 规则和显式 ask 规则在任何模式(包括 bypassPermissions)下都生效——这就是你"围栏"的真正钉子。

常见问题:新手容易把 acceptEdits 当成"全自动"。注意它仍然会在执行 shell 命令(如 npm run build)时停下来问你,除非你用规则预先放行。

步骤 3:在会话中切换模式,并把默认值持久化

切换模式不是靠在聊天里打字,而是用专门的控制:

{
  "permissions": {
    "defaultMode": "acceptEdits"
  }
}

有三档默认不在循环里:auto(需账号满足条件,首次会弹 opt-in)、bypassPermissions(需 --permission-mode bypassPermissions 或 --dangerously-skip-permissions 启动)、dontAsk(永不进循环,只能用 --permission-mode dontAsk 启动)。

预期结果:按 Shift+Tab,状态栏文字应从 Ask before edits(default)变成 Edit automatically(acceptEdits)再变成 Plan mode(plan)。

常见问题:defaultMode: "auto" 写在项目/本地配置里会被忽略——auto 只接受写在用户级配置里的默认值。

步骤 4:动手写规则——Tool(specifier) 语法详解

规则统一遵循 Tool 或 Tool(specifier) 两种形式。求值顺序固定为 deny → ask → allow,首个匹配决定结果,规则的"具体程度"不会改变顺序。这意味着一条宽泛的 deny(如 Bash(aws *))会压倒更窄的 allow(如 Bash(aws s3 ls))——deny 不能被 allow 开口子。

匹配整类工具:直接写工具名,不带括号。Bash 匹配所有 shell 命令;作为 deny 规则时,它会把该工具从 Claude 的上下文里整个移除(Claude 根本看不到它能跑 bash)。

精细匹配:括号内写 specifier。示例:

Bash(npm run build)       # 精确匹配该命令
Read(./.env)              # 匹配读取当前目录的 .env
WebFetch(domain:example.com)  # 匹配对该域名的抓取

通配符 *:Bash 规则支持 glob,* 可在任意位置,单个 * 可跨多个参数。

{
  "permissions": {
    "allow": [
      "Bash(npm run *)",
      "Bash(git commit *)",
      "Bash(* --version)"
    ],
    "deny": [
      "Bash(git push *)"
    ]
  }
}

最容易踩的两个坑:

  1. 空格敏感:Bash(ls *) 匹配 ls -la 但不匹配 lsof;而 Bash(ls*) 两者都匹配。对话框里选"Yes, don't ask again"生成的是带空格形式。末尾的 :*(如 Bash(ls:*))等价于带空格的尾通配,但只在结尾有效——写在中间(如 Bash(git:* push))会被当字面冒号。
  2. 不能用参数语法堵 bash:Bash(command:rm *) 是可绕过的(复合命令能逃逸),Claude Code 会忽略它并报警。正确写法是 Bash(rm *)。

MCP 工具的匹配:deny/ask 可用 mcp__* 一键禁用所有 MCP 工具;allow 则必须在 mcp__<服务器名>__ 前缀之后才支持 glob,如 mcp__github__get_*。未锚定的 allow glob(如 *、mcp__*)会被跳过并警告。

步骤 5:摸清 settings.json 的三级位置与优先级

权限规则可以分散在多个配置文件里,它们会合并生效。从最高到最低:

级别 路径 特点
托管/企业(managed) 系统级,由 IT 下发 最高,不可被覆盖,可锁定模式
用户(user) ~/.claude/settings.json 你的全局默认
项目(project) <项目>/.claude/settings.json 随仓库走,可提交版本控制,团队共享
本地(local) <项目>/.claude/settings.local.json 个人覆盖,建议加入 .gitignore

求值与合并:各级的 allow/ask/deny 会合并;同一调用按 deny→ask→allow 顺序首次匹配定胜负。托管层有两个"杀手锏"开关:permissions.disableBypassPermissionsMode: "disable" 禁用越权模式,permissions.disableAutoMode: "disable" 禁用 auto 模式——这两个最适合放在托管层,因为那里才无法被下属层级覆盖。

预期结果:运行 claude 后输入 /permissions,会列出所有生效规则并标注它来自哪个 settings 文件。这是排查"为什么这条规则没生效"的第一手段。

常见问题:"我在项目里写了 allow,为什么不生效?" 多半是用户级或托管级有一条更宽的 deny 命中了同一调用。用 /permissions 逐条核对来源即可定位。

步骤 6:用 dontAsk 给"脚本化"项目上锁

如果你的第一个项目其实是一个会被 CI 反复调用的脚本,你想要的不是"少打扰",而是"只准干我批准过的事"。这正是 dontAsk 的舞台:它自动拒绝一切未预先批准的工具。配合 claude -p "..." --permission-mode dontAsk,能保证无人值守时 Claude 绝不越界。

预期结果:在 dontAsk 下,任何不在 allow 列表里的工具调用都会被静默拒绝,任务会因"工具不可用"而中止或改道,但绝不会偷偷执行。

实战案例:给一个 Node 项目配"本地构建、禁止外发"的围栏

假设你的项目 ~/my-app,目标:允许 Claude 自由读代码、自由跑本地构建与测试、自由编辑工作区文件,但禁止 git push、禁止任何网络外发抓取、禁止删除仓库外的目录。

第 1 步,创建项目级配置:

mkdir -p ~/my-app/.claude

编辑 ~/my-app/.claude/settings.json:

{
  "permissions": {
    "defaultMode": "acceptEdits",
    "allow": [
      "Bash(npm run *)",
      "Bash(npm test *)",
      "Bash(npm install)",
      "Bash(node *)",
      "Bash(git status)",
      "Bash(git diff *)",
      "Bash(git log *)",
      "Bash(git add *)",
      "Bash(git commit *)"
    ],
    "deny": [
      "Bash(git push *)",
      "WebFetch",
      "Bash(rm -rf /*)",
      "Bash(curl *)",
      "Read(./.env)",
      "Read(./.env.*)"
    ]
  }
}

逐条解读:defaultMode 设为 acceptEdits 让文件编辑免提示,但 shell 命令仍需批准——allow 列表把构建/测试/git 读取放行;deny 里 Bash(git push *) 拦住误推送,WebFetch(裸工具名)把网络抓取能力整体摘除,Read(./.env) 保护本地密钥,rm -rf /* 兜底防止误删。

第 2 步,把个人偏好隔离开,避免污染团队配置:

// ~/my-app/.claude/settings.local.json (加入 .gitignore)
{
  "permissions": {
    "allow": ["Bash(pnpm *)"]
  }
}

并把 settings.local.json 写进 .gitignore。

第 3 步,启动并验证:

cd ~/my-app
claude

进入会话后输入 /permissions,应看到三组规则分别标注来源 project 与 local。

第 4 步,跑第一个任务验证围栏是否就位:

> 帮我跑一遍测试,然后把当前改动提交成一个 fix: 开头的 commit

预期:npm test 与 git commit 因命中 allow 而免提示直接执行;若你随后追加一句"顺便推到远端",git push 会因命中 deny 而被拦截——围栏生效。

工作流程图

flowchart TD
    A[Claude 发起一次工具调用] --> B{命中 deny 规则?}
    B -- 是 --> X[❌ 拒绝<br/>任何模式都拦]
    B -- 否 --> C{命中 ask 规则?}
    C -- 是 --> Y[⏸ 弹窗确认]
    C -- 否 --> D{命中 allow 规则?}
    D -- 是 --> Z[✅ 免提示执行]
    D -- 否 --> E{当前模式放行?}
    E -- default/plan --> W[⏸ 弹窗确认]
    E -- acceptEdits & 文件操作 --> Z
    E -- bypassPermissions --> Z
    E -- dontAsk --> X
    Y -- 用户批准 --> Z
    Y -- 用户拒绝 --> X
    W -- 用户批准 --> Z
    W -- 用户拒绝 --> X

核心规律:deny 永远最先判,且无法被 allow 翻盘;模式只在"没有任何规则命中"时才决定是否需要问你。

延伸阅读

训练营适用性评估

参考来源

  1. Configure permissions — Claude Code Docs — 官方权威:规则语法、求值顺序(deny→ask→allow)、各工具 specifier 与通配符行为。
  2. Choose a permission mode — Claude Code Docs — 官方权威:六档模式对照表、各平台切换方式、受保护路径与 dontAsk/bypass 说明。
  3. Claude Code Permissions: Allow Lists, Deny Rules, and Sandboxing (2026) — 实践向博客:allow/deny 规则与沙箱结合的落地指南。
  4. Claude Code Permission Modes: Default, acceptEdits, Bypass — explainx — 模式取舍的场景化解读,补充官方表格之外的选择建议。
  5. Permission Rule Syntax — codingnomads — 细粒度权限规则的语法拆解,含大量可复制示例。

[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。

51学通信知识星球海报-扫码加入