feat: 在后台管理面板增加 API Token 配置与生成功能
This commit is contained in:
1 parent
fe08cd27ff
commit
3f91f38a88
2 files changed
+76
No files matched your search
@@ -68,6 +68,28 @@ export const actions: Actions = {
|
|||||||
return fail(500, { error: '保存站点信息失败' });
|
return fail(500, { error: '保存站点信息失败' });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
updateApiToken: async ({ request, platform }) => {
|
||||||
|
const db = platform?.env?.DB;
|
||||||
|
if (!db) return fail(500, { error: '数据库未连接' });
|
||||||
|
|
||||||
|
const data = await request.formData();
|
||||||
|
const token = data.get('agent_api_token')?.toString() || '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
await db
|
||||||
|
.prepare(
|
||||||
|
`INSERT INTO settings (key, value, updated_at)
|
||||||
|
VALUES (?, ?, CURRENT_TIMESTAMP)
|
||||||
|
ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = CURRENT_TIMESTAMP`
|
||||||
|
)
|
||||||
|
.bind('agent.api_token', token)
|
||||||
|
.run();
|
||||||
|
return { success: true };
|
||||||
|
} catch (err: unknown) {
|
||||||
|
console.error('Failed to update api token', err);
|
||||||
|
return fail(500, { error: '保存 API Token 失败' });
|
||||||
|
}
|
||||||
|
},
|
||||||
updateAliases: async ({ request, platform }) => {
|
updateAliases: async ({ request, platform }) => {
|
||||||
const db = platform?.env?.DB;
|
const db = platform?.env?.DB;
|
||||||
if (!db) return fail(500, { error: '数据库未连接' });
|
if (!db) return fail(500, { error: '数据库未连接' });
|
||||||
|
|||||||
@@ -16,6 +16,17 @@
|
|||||||
let avatarEnabled = $state(initialData.settings['site.avatar_enabled'] !== 'false');
|
let avatarEnabled = $state(initialData.settings['site.avatar_enabled'] !== 'false');
|
||||||
let avatarUrl = $state(initialData.settings['site.avatar_url'] || '');
|
let avatarUrl = $state(initialData.settings['site.avatar_url'] || '');
|
||||||
|
|
||||||
|
let apiToken = $state(initialData.settings['agent.api_token'] || '');
|
||||||
|
let showApiToken = $state(false);
|
||||||
|
|
||||||
|
function generateApiToken() {
|
||||||
|
const randomPart = Array.from(crypto.getRandomValues(new Uint8Array(16)))
|
||||||
|
.map((b) => b.toString(16).padStart(2, '0'))
|
||||||
|
.join('');
|
||||||
|
apiToken = 'bf_agent_' + randomPart;
|
||||||
|
showApiToken = true;
|
||||||
|
}
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (form?.success) {
|
if (form?.success) {
|
||||||
addToast('设置保存成功!', 'success');
|
addToast('设置保存成功!', 'success');
|
||||||
@@ -131,6 +142,49 @@
|
|||||||
<span class="value">Cloudflare Access (Zero Trust)</span>
|
<span class="value">Cloudflare Access (Zero Trust)</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="settings-card full-width">
|
||||||
|
<h3>API 与 AI 集成 (Agent/MCP)</h3>
|
||||||
|
<p class="desc">
|
||||||
|
配置允许 AI 或第三方工具直接管理文章的 API 访问令牌 (Token)。请求 API 时请在 HTTP Header
|
||||||
|
中添加 <code>Authorization: Bearer <Token></code>。
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form
|
||||||
|
method="POST"
|
||||||
|
action="?/updateApiToken"
|
||||||
|
use:enhance={() => {
|
||||||
|
return async ({ update }) => {
|
||||||
|
update({ reset: false });
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
class="alias-form"
|
||||||
|
>
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="agent_api_token">API Token</label>
|
||||||
|
<div style="display: flex; gap: 10px; align-items: center; width: 100%;">
|
||||||
|
<TextInput
|
||||||
|
type={showApiToken ? 'text' : 'password'}
|
||||||
|
id="agent_api_token"
|
||||||
|
name="agent_api_token"
|
||||||
|
bind:value={apiToken}
|
||||||
|
placeholder="留空则禁用对外 API 访问"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
variant="secondary"
|
||||||
|
onclick={() => (showApiToken = !showApiToken)}
|
||||||
|
>
|
||||||
|
{showApiToken ? '隐藏' : '显示'}
|
||||||
|
</Button>
|
||||||
|
<Button type="button" variant="secondary" onclick={generateApiToken}>自动生成</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-actions">
|
||||||
|
<Button type="submit" variant="primary">保存 Token</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if activeTab === 'appearance'}
|
{#if activeTab === 'appearance'}
|
||||||
|
|||||||
Reference in new issue
Block a user