文档/Permission 权限系统
通用开发

Permission 权限系统

Permission 权限系统

概述

插件权限系统用于控制插件对敏感资源和 API 的访问。从 SDK API 251212 版本开始,所有权限声明都会被强制校验;未声明合法 sdkapi 的插件会在运行时被直接阻断。

介绍

权限声明强调最小授权,通过 permissionspermissionReasons 对用户解释用途,提升授权通过率。

快速开始

1. 在 manifest.json 中声明权限

EXAMPLE.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 或版本较低:

EXAMPLE.JSON
{
  "sdkapi": 260428,
  "permissions": {
    "required": ["clipboard.read"],
    "optional": []
  }
}

技术原理

  • 权限校验由权限中心统一管理,sdkapi 达到门槛才启用完整校验。
  • 授权结果持久化在 <appData>/config/permission/ 下的 SQLite 权限存储;旧 permissions.json 仅用于一次性迁移,不再是可写真相源。

API 参考

在 Prelude (index.js) 中检查权限

EXAMPLE.JAVASCRIPT
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) 中使用

EXAMPLE.TYPESCRIPT
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 必需权限:

EXAMPLE.JSON
{
  "sdkapi": 260428,
  "permissions": {
    "required": ["storage.sqlite"],
    "optional": []
  },
  "permissionReasons": {
    "storage.sqlite": "将插件业务数据存储到本地 SQLite 数据库"
  }
}
EXAMPLE.TS
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. 最小权限原则

只声明实际需要的权限:

EXAMPLE.JSON
// ✅ 好的做法
"permissions": {
  "required": ["clipboard.read"],
  "optional": []
}

// ❌ 避免
"permissions": {
  "required": ["fs.read", "fs.write", "fs.execute", "system.shell"]
}

2. 提供权限说明

EXAMPLE.JSON
"permissionReasons": {
  "clipboard.read": "读取剪贴板中的待翻译文本",
  "network.internet": "连接 Google 翻译 API"
}

3. 优雅降级

EXAMPLE.JAVASCRIPT
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. 区分必需和可选权限

EXAMPLE.JSON
"permissions": {
  "required": ["clipboard.read"],  // 核心功能必需
  "optional": ["network.internet"] // 增强功能可选
}

用户界面

用户可以在以下位置管理插件权限:

  1. 插件详情页 > 权限 Tab: 查看和管理单个插件的权限
  2. 运行时弹窗: 插件首次请求权限时显示

常见问题

Q: 为什么我的插件会显示 SDKAPI_BLOCKED

A: 您的 manifest.json 未声明 sdkapi、使用了非法 / 未受支持 marker,或版本低于 251212。请更新为当前受支持的版本:

EXAMPLE.JSON
"sdkapi": 260428

Q: 如何处理用户拒绝权限?

A: 提供降级方案或清晰的错误提示:

EXAMPLE.JAVASCRIPT
const granted = await permission.request('clipboard.read')
if (!granted) {
  // 显示提示,引导用户手动输入或授权
  feature.pushItems([{
    title: '需要剪贴板权限',
    subtitle: '请在插件设置中授予权限'
  }])
}

Q: 权限数据存储在哪里?

A: 权限授予数据存储在 <appData>/config/permission/ 下的 SQLite 权限库;permissions.json 仅在升级旧安装时作为历史迁移输入保留。