首页 / 浏览器扩展开发入门教程 / permissions 与 host_permissions

浏览器扩展开发入门教程

permissions 与 host_permissions

本教程共 56 篇 · 第 10 篇 · 更新于 2026-08-13 · 约 7 分钟阅读

清单manifestpermissionshost_permissions权限activeTab

本节目标:学完你能分清 permissions 和 host_permissions 两类声明式权限,知道常用权限名各自代表什么能力,并理解为什么 activeTab 比直接要 host_permissions 更可取。

扩展不是想干什么就干什么。浏览器出于安全考虑,要求扩展在清单里”先报备、再用权”。你声明了某个权限,代码里才能调用对应的 API;没声明就去调用,浏览器会直接报错。这一节讲清楚 Manifest V3 里两种最常被混淆的权限声明:permissions 和 host_permissions。

10-1 为什么要声明权限

想想一个密码管理器扩展:它需要读写你存过的账号,需要往当前网页的输入框里填内容,需要跨域把数据同步到服务器。这些动作如果随便一个网页脚本也能做,那就乱套了。所以浏览器把”能力”收口成权限,扩展必须在安装前就告诉用户”我要这些权限”,用户点头后才生效。

好处有两个:一是用户安装时能看到风险提示,决定是否信任;二是浏览器按最小可用原则收紧,没声明的接口一律不准用。Manifest V3 尤其强调”按需申请”,过度申请不仅难通过商店审核,还会吓跑用户。

权限写在清单顶层,是字符串数组。看一份完整示例:

{
  "name": "Permissions Extension",
  "version": "1.0",
  "manifest_version": 3,
  "permissions": [
    "activeTab",
    "contextMenus",
    "storage"
  ],
  "optional_permissions": [
    "topSites"
  ],
  "host_permissions": [
    "https://www.developer.chrome.com/*"
  ],
  "optional_host_permissions": [
    "https://*/*",
    "http://*/*"
  ]
}

这里出现了四个数组:permissions、optional_permissions、host_permissions、optional_host_permissions。前两个是 API 级权限,后两个是网站级宿主权限。下面拆开讲。

10-2 permissions 与 host_permissions 的根本区别

这是全节最关键点,我多说几句。

permissions 管的是”扩展能调用哪些浏览器 API”。比如 storage 让你用 chrome.storage 存数据,contextMenus 让你加右键菜单,alarms 让你设定时任务。它和”具体哪个网站”无关,是一种横向的能力开关。

host_permissions 管的是”扩展能访问哪些网址的内容”。比如你声明了 https://www.developer.chrome.com/*,扩展就能对该站发起跨域请求、读取其页面信息、在内容脚本里与之交互。它针对的是网站来源,是一种纵向的范围授权。

一句话区分:permissions 是”能做什么动作”,host_permissions 是”能在哪些网站上做”。 两者经常要配合使用——例如内容脚本要注入到某站并读取其 DOM,既要在 content_scripts.matches 里匹配该站,通常还要在 host_permissions 里声明该站(取决于具体 API)。

Note

注意 host_permissions 和 content_scripts 的 matches 不是一回事。matches 决定”脚本注入哪些页面”,host_permissions 决定”扩展对该站拥有哪些跨域/读取能力”。前者是注入范围,后者是权限范围。

10-3 几个常用的 permissions 名称

下面列的是 MV3 里最常见、最该认识的 API 权限名。不是全部,但覆盖了绝大多数扩展会碰到的:

  • storage:读写 chrome.storage(本地/同步存储)。几乎每个扩展都用,且对用户无感、无警告,强烈建议。
  • activeTab:用户主动触发时(比如点了工具栏按钮),临时获得当前标签页的访问权。详见 10-4。
  • scripting:用 chrome.scripting 动态注入脚本或样式。配合 activeTab 或 host_permissions 使用。
  • tabs:访问标签页的 url、title 等元数据。注意有 tabs 权限不代表能读页面内容,那归 host_permissions 和内容脚本管。
  • bookmarks:增删改书签。
  • cookies:读写 cookies。
  • downloads:触发和管理下载。
  • history:查询、删除浏览历史。
  • notifications:弹出系统通知。
  • contextMenus:添加右键菜单项。
  • alarms:注册周期性或定时任务,替代 setInterval。
  • declarativeNetRequest:MV3 中修改/拦截网络请求的唯一正规方式。
  • sidePanel:控制侧边栏开关(配合清单的 side_panel 字段)。
Tip

权限会触发安装时的警告横幅。比如要 history、要 <all_urls> 宿主权限,用户会看到明显风险提示。能用 activeTab 代替宿主权限的场景,尽量用 activeTab,警告更少、用户更放心。

10-4 activeTab:最小权限的代表

activeTab 值得单独拎出来,因为它最能体现 MV3 的”最小权限”思想。

普通情况下,要操作某个标签页的页面(比如往里注入脚本改背景色),你得在 host_permissions 里声明该站,甚至 <all_urls>。这意味着扩展”随时”都能动这些页面。

activeTab 换了个思路:只有当用户主动与扩展交互时(点击工具栏按钮、执行命令、点右键菜单),扩展才在”当前这个标签页”临时获得访问权,且只限这一次动作。权限在用户导航离开当前页面、或关掉标签时收回;只是切到别的标签页再切回来,授权还在。

{
  "name": "Page Redder",
  "version": "2.0",
  "manifest_version": 3,
  "permissions": [
    "activeTab",
    "scripting"
  ],
  "action": {
    "default_title": "Make this page red"
  }
}

配上后台脚本,用户一点按钮就把当前页染红:

function reddenPage() {
  document.body.style.backgroundColor = 'red';
}

chrome.action.onClicked.addListener((tab) => {
  if (!tab.url.includes('chrome://')) {
    chrome.scripting.executeScript({
      target: { tabId: tab.id },
      func: reddenPage
    });
  }
});

这样做的好处:扩展不需要任何宿主权限,安装时零警告,用户信任度高。能不用 host_permissions 的场景,优先用 activeTab。

10-5 host_permissions:网站级别的授权

当你确实需要”长期、自动”地访问某些网站时,才用 host_permissions。比如一个翻译扩展要在后台静默抓取目标网页内容,或一个比价扩展要读取电商页面。

{
  "name": "My extension",
  "manifest_version": 3,
  "host_permissions": [
    "https://api.example.com/*",
    "https://*.shop.com/*"
  ]
}

host_permissions 的值同样是匹配模式(和 content_scripts 的 matches 语法一致),支持 https://*.example.com/*<all_urls> 等写法。声明后,扩展对这些站点可以发起跨域 fetch、读取响应、在内容脚本中与之充分交互。

Warning

我建议你把 host_permissions 收窄到真正需要的域名,别图省事写 <all_urls>。一来安装警告吓人,二来商店审核对”过度申请宿主权限”很敏感,三来这也是对用户数据的尊重。

10-6 optional_permissions 与 optional_host_permissions 简介

前面示例里还出现了 optional_permissions 和 optional_host_permissions。它们是”可选权限”,安装时不申请、不显示警告,等用户用到某功能时再通过代码 chrome.permissions.request() 弹窗询问。

这套机制适合”高级功能才需要”的权限。比如你的扩展基础功能只用 storage,但有个”显示热门网站”的进阶功能才需要 topSites,那就把 topSites 放进 optional_permissions,用户点开该功能时再申请。

这一节不展开 request 的写法(属于权限模型的后续章节),你只要知道它们的定位:主权限写 permissions/host_permissions,锦上添花、可能惹警告的权限写 optional 系列。

10-7 写一份权限声明清单

把这一节的内容收拢,一份”克制而清晰”的权限声明长这样:

{
  "manifest_version": 3,
  "name": "轻量划线笔记",
  "version": "1.0.0",
  "description": "在网页上划词做笔记,本地保存。",
  "permissions": [
    "storage",
    "activeTab",
    "scripting"
  ],
  "host_permissions": [
    "https://*.my-note-sync.com/*"
  ],
  "content_scripts": [
    {
      "matches": ["https://*/*"],
      "js": ["content-script.js"],
      "run_at": "document_idle"
    }
  ]
}

这份清单的原则很清楚:基础能力只拿 storage;操作页面靠 activeTab + scripting 临时授权,不申请全网宿主权限;只有真正要同步的域名才写进 host_permissions。权限声明这件事,少即是多。下一章我们回头扫一遍清单里其余几个常用字段——options_ui、side_panel、web_accessible_resources、content_security_policy、commands,把它们也纳入你的清单工具箱。