Permission 权限系统
Permission 权限系统
概述
插件权限系统用于控制插件对敏感资源和 API 的访问。从 SDK API 251212 版本开始,所有权限声明都会被强制校验;未声明合法 sdkapi 的插件会在运行时被直接阻断。
介绍
权限声明强调最小授权,通过 permissions 与 permissionReasons 对用户解释用途,提升授权通过率。
快速开始
1. 在 manifest.json 中声明权限
{
"id": "com.example.plugin",
"name": "My Plugin",
"version": "1.0.0",
"sdkapi": 260428,
"permissions": {
"required": ["clipboard.read", "network.internet"],
"optional": ["storage.shared"]
},
"permissionReasons": {
"clipboard.read": "需要读取剪贴板以获取待翻译文本",
"network.internet": "需要访问翻译 API 服务"
}
}
2. 权限分类
| 类别 | 权限 ID | 风险等级 | 说明 |
|---|---|---|---|
| 文件系统 | fs.read | 中 | 读取用户文件 |
fs.write | 高 | 写入/修改文件 | |
fs.execute | 高 | 执行文件或脚本 | |
| 剪贴板 | clipboard.read | 中 | 读取剪贴板内容 |
clipboard.write | 低 | 写入剪贴板内容 | |
| 网络 | network.local | 低 | 访问本地网络 |
network.internet | 中 | 访问互联网 | |
network.download | 中 | 下载文件到本地 | |
| 系统 | system.shell | 高 | 执行系统命令 |
system.notification | 低 | 发送系统通知 | |
system.tray | 中 | 操作系统托盘 | |
| 智能 | intelligence.basic | 低 | 基础智能能力 |
intelligence.admin | 高 | 管理级智能能力 | |
intelligence.agents | 高 | 智能体系统 | |
| 存储 | storage.plugin | 低 | 插件私有存储(自动授予) |
storage.shared | 中 | 跨插件共享存储 | |
storage.sqlite | 中 | 访问插件本地 SQLite 数据库 | |
| 窗口 | window.create | 低 | 创建窗口(自动授予) |
window.capture | 高 | 屏幕截图 |
3. 风险等级说明
- 低风险 (low): 自动授予或一次确认即可
- 中风险 (medium): 需要用户明确授权
- 高风险 (high): 需要用户二次确认,显示警告
4. 默认自动授予的权限
以下权限会自动授予,无需用户确认:
storage.plugin- 插件私有存储clipboard.write- 写入剪贴板window.create- 创建窗口
SDK 版本与权限校验
sdkapi 字段
sdkapi 字段决定插件能否进入权限校验运行时:
| sdkapi 值 | 权限校验 | 说明 |
|---|---|---|
| 未声明 | 阻断 | 运行时返回 SDKAPI_BLOCKED |
| < 251212 | 阻断 | 运行时返回 SDKAPI_BLOCKED |
| 未列入支持列表 | 阻断 | 非 canonical 或未来 marker 返回 SDKAPI_BLOCKED |
| 受支持且 >= 251212 | 启用 | 完整权限校验 |
迁移指南
如果您的插件未声明 sdkapi 或版本较低:
{
"sdkapi": 260428,
"permissions": {
"required": ["clipboard.read"],
"optional": []
}
}
技术原理
- 权限校验由权限中心统一管理,
sdkapi达到门槛才启用完整校验。 - 授权结果持久化在
<appData>/config/permission/下的 SQLite 权限存储;旧permissions.json仅用于一次性迁移,不再是可写真相源。
API 参考
在 Prelude (index.js) 中检查权限
const { permission } = globalThis
// 检查是否有权限
const hasPermission = await permission.check('clipboard.read')
// 请求权限(会触发用户确认弹窗)
const granted = await permission.request('clipboard.read', '需要读取剪贴板内容')
if (granted) {
// 使用 clipboard API
const text = clipboard.readText()
}
在 Surface (Vue) 中使用
import { usePermission } from '@talex-touch/utils/plugin/sdk'
const { check, request, status } = usePermission()
// 检查权限
const hasClipboard = await check('clipboard.read')
// 请求权限
const granted = await request('network.internet', '需要访问翻译服务')
// 获取所有权限状态
const allStatus = await status()
SQLite SDK(sdkapi >= 260215)
当使用 usePluginSqlite() 时,需要在 manifest 中声明 storage.sqlite 必需权限:
{
"sdkapi": 260428,
"permissions": {
"required": ["storage.sqlite"],
"optional": []
},
"permissionReasons": {
"storage.sqlite": "将插件业务数据存储到本地 SQLite 数据库"
}
}
import { usePluginSqlite } from '@talex-touch/utils/plugin/sdk'
const sqlite = usePluginSqlite()
await sqlite.execute(
'CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, created_at TEXT NOT NULL)'
)
await sqlite.execute(
'INSERT INTO notes (title, created_at) VALUES (?, ?)',
['hello', new Date().toISOString()]
)
const result = await sqlite.query<{ id: number; title: string }>(
'SELECT id, title FROM notes ORDER BY id DESC LIMIT 10'
)
console.log(result.rows)
最佳实践
1. 最小权限原则
只声明实际需要的权限:
// ✅ 好的做法
"permissions": {
"required": ["clipboard.read"],
"optional": []
}
// ❌ 避免
"permissions": {
"required": ["fs.read", "fs.write", "fs.execute", "system.shell"]
}
2. 提供权限说明
"permissionReasons": {
"clipboard.read": "读取剪贴板中的待翻译文本",
"network.internet": "连接 Google 翻译 API"
}
3. 优雅降级
async function translateText(text) {
const hasNetwork = await permission.check('network.internet')
if (!hasNetwork) {
// 请求权限或提示用户
const granted = await permission.request('network.internet')
if (!granted) {
return { error: '需要网络权限才能翻译' }
}
}
// 正常翻译逻辑
return await http.post('...')
}
4. 区分必需和可选权限
"permissions": {
"required": ["clipboard.read"], // 核心功能必需
"optional": ["network.internet"] // 增强功能可选
}
用户界面
用户可以在以下位置管理插件权限:
- 插件详情页 > 权限 Tab: 查看和管理单个插件的权限
- 运行时弹窗: 插件首次请求权限时显示
常见问题
Q: 为什么我的插件会显示 SDKAPI_BLOCKED?
A: 您的 manifest.json 未声明 sdkapi、使用了非法 / 未受支持 marker,或版本低于 251212。请更新为当前受支持的版本:
"sdkapi": 260428
Q: 如何处理用户拒绝权限?
A: 提供降级方案或清晰的错误提示:
const granted = await permission.request('clipboard.read')
if (!granted) {
// 显示提示,引导用户手动输入或授权
feature.pushItems([{
title: '需要剪贴板权限',
subtitle: '请在插件设置中授予权限'
}])
}
Q: 权限数据存储在哪里?
A: 权限授予数据存储在 <appData>/config/permission/ 下的 SQLite 权限库;permissions.json 仅在升级旧安装时作为历史迁移输入保留。