app.keychain - 安全凭证存储 API
使用 macOS Keychain 安全存储敏感数据(API 密钥、令牌、密码等)。
权限: 需在 manifest 中声明
keychain(L1 standard) 隔离: 每个插件的凭证互相隔离,无法访问其他插件的凭证。
方法
app.keychain.set(key, value)
存储凭证。如果 key 已存在则更新。
参数:
key(string) - 凭证名称value(string) - 凭证值
返回值: boolean, error
local ok, err = app.keychain.set("api_key", "sk-xxxxxxxxxxxx")
if not ok then
app.log.error("存储失败: " .. err)
end
app.keychain.get(key)
读取凭证。
参数:
key(string) - 凭证名称
返回值: string|nil, error - 凭证值或 nil(不存在时返回 nil 且无 error)
local token, err = app.keychain.get("api_key")
if token then
app.log.info("Token 长度: " .. #token)
elseif err then
app.log.error("读取失败: " .. err)
else
app.log.info("凭证不存在")
end
app.keychain.delete(key)
删除凭证。删除不存在的 key 也返回成功。
参数:
key(string) - 凭证名称
返回值: boolean, error
local ok, err = app.keychain.delete("api_key")
app.keychain.has(key)
检查凭证是否存在。
参数:
key(string) - 凭证名称
返回值: boolean
if app.keychain.has("api_key") then
local key = app.keychain.get("api_key")
-- 使用 key...
end
示例
API 密钥管理
function MyPlugin:handleSetup(context)
-- 检查是否已配置
if app.keychain.has("github_token") then
local result = app.dialog.alert({
title = "已配置",
message = "GitHub Token 已存在,要更新吗?",
buttons = {"更新", "取消"}
})
if result ~= 1 then return end
end
-- 通过表单收集凭证
local result = app.dialog.form({
title = "配置 GitHub Token",
fields = {
{type = "text", id = "token", label = "Personal Access Token", default = ""}
}
})
if result and result.token ~= "" then
local ok, err = app.keychain.set("github_token", result.token)
if ok then
app.notification.show("配置成功", "GitHub Token 已安全存储")
else
app.dialog.alert({title = "错误", message = "存储失败: " .. err})
end
end
end
function MyPlugin:handleFetch(context)
local token = app.keychain.get("github_token")
if not token then
app.dialog.alert({title = "未配置", message = "请先运行「配置 Token」"})
return
end
local resp = app.http.get("https://api.github.com/user", {
["Authorization"] = "Bearer " .. token,
["Accept"] = "application/vnd.github.v3+json"
})
if resp and resp.status == 200 then
local user = app.json.parse(resp.body)
app.notification.show("GitHub", "登录为: " .. user.login)
end
end
多凭证管理
function MyPlugin:handleManageCredentials(context)
local keys = {"api_key", "secret", "webhook_url"}
local items = {}
for _, key in ipairs(keys) do
local exists = app.keychain.has(key)
table.insert(items, key .. ": " .. (exists and "已配置" or "未配置"))
end
local selected = app.dialog.choose(items, {
title = "凭证管理",
message = "选择要操作的凭证"
})
if selected then
local key = keys[1] -- 根据选中项确定 key
for i, item in ipairs(items) do
if item == selected then key = keys[i] end
end
local result = app.dialog.alert({
title = key,
message = app.keychain.has(key) and "当前已配置" or "当前未配置",
buttons = {"设置", "删除", "取消"}
})
if result == 1 then
local input = app.dialog.form({
title = "设置 " .. key,
fields = {{type = "text", id = "value", label = "值"}}
})
if input then
app.keychain.set(key, input.value)
end
elseif result == 2 then
app.keychain.delete(key)
app.notification.show("已删除", key)
end
end
end
注意事项
- 插件隔离:每个插件的凭证互相隔离,不同插件无法读取对方的凭证
- 存储安全:使用 macOS Keychain(
kSecClassGenericPassword),数据加密存储 - 仅支持字符串:
value必须是字符串类型,如需存储复杂数据请先 JSON 序列化 - 持久化:凭证存储在系统 Keychain 中,卸载插件不会自动清除
- 访问级别:使用
kSecAttrAccessibleAfterFirstUnlock,设备首次解锁后即可访问