refactor(auth): 将 Linux DO OAuth 配置迁移到系统设置
- 将 LinuxDo Connect 配置从环境变量迁移到数据库持久化 - 在管理后台系统设置中添加 LinuxDo OAuth 配置项 - 简化部署流程,无需修改 docker-compose.override.yml 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,11 @@ export interface SystemSettings {
|
||||
turnstile_enabled: boolean
|
||||
turnstile_site_key: string
|
||||
turnstile_secret_key_configured: boolean
|
||||
// LinuxDo Connect OAuth login (end-user SSO)
|
||||
linuxdo_connect_enabled: boolean
|
||||
linuxdo_connect_client_id: string
|
||||
linuxdo_connect_client_secret_configured: boolean
|
||||
linuxdo_connect_redirect_url: string
|
||||
// Identity patch configuration (Claude -> Gemini)
|
||||
enable_identity_patch: boolean
|
||||
identity_patch_prompt: string
|
||||
@@ -60,6 +65,10 @@ export interface UpdateSettingsRequest {
|
||||
turnstile_enabled?: boolean
|
||||
turnstile_site_key?: string
|
||||
turnstile_secret_key?: string
|
||||
linuxdo_connect_enabled?: boolean
|
||||
linuxdo_connect_client_id?: string
|
||||
linuxdo_connect_client_secret?: string
|
||||
linuxdo_connect_redirect_url?: string
|
||||
enable_identity_patch?: boolean
|
||||
identity_patch_prompt?: string
|
||||
}
|
||||
|
||||
@@ -1766,6 +1766,24 @@ export default {
|
||||
cloudflareDashboard: 'Cloudflare Dashboard',
|
||||
secretKeyHint: 'Server-side verification key (keep this secret)',
|
||||
secretKeyConfiguredHint: 'Secret key configured. Leave empty to keep the current value.' },
|
||||
linuxdo: {
|
||||
title: 'LinuxDo Connect Login',
|
||||
description: 'Configure LinuxDo Connect OAuth for Sub2API end-user login',
|
||||
enable: 'Enable LinuxDo Login',
|
||||
enableHint: 'Show LinuxDo login on the login/register pages',
|
||||
clientId: 'Client ID',
|
||||
clientIdPlaceholder: 'e.g., hprJ5pC3...',
|
||||
clientIdHint: 'Get this from Connect.Linux.Do',
|
||||
clientSecret: 'Client Secret',
|
||||
clientSecretPlaceholder: '********',
|
||||
clientSecretHint: 'Used by backend to exchange tokens (keep it secret)',
|
||||
clientSecretConfiguredPlaceholder: '********',
|
||||
clientSecretConfiguredHint: 'Secret configured. Leave empty to keep the current value.',
|
||||
redirectUrl: 'Redirect URL',
|
||||
redirectUrlPlaceholder: 'https://your-domain.com/api/v1/auth/oauth/linuxdo/callback',
|
||||
redirectUrlHint:
|
||||
'Must match the redirect URL configured in Connect.Linux.Do (must be an absolute http(s) URL)'
|
||||
},
|
||||
defaults: {
|
||||
title: 'Default User Settings',
|
||||
description: 'Default values for new users',
|
||||
|
||||
@@ -1911,6 +1911,23 @@ export default {
|
||||
cloudflareDashboard: 'Cloudflare Dashboard',
|
||||
secretKeyHint: '服务端验证密钥(请保密)',
|
||||
secretKeyConfiguredHint: '密钥已配置,留空以保留当前值。' },
|
||||
linuxdo: {
|
||||
title: 'LinuxDo Connect 登录',
|
||||
description: '配置 LinuxDo Connect OAuth,用于 Sub2API 用户登录',
|
||||
enable: '启用 LinuxDo 登录',
|
||||
enableHint: '在登录/注册页面显示 LinuxDo 登录入口',
|
||||
clientId: 'Client ID',
|
||||
clientIdPlaceholder: '例如:hprJ5pC3...',
|
||||
clientIdHint: '从 Connect.Linux.Do 后台获取',
|
||||
clientSecret: 'Client Secret',
|
||||
clientSecretPlaceholder: '********',
|
||||
clientSecretHint: '用于后端交换 token(请保密)',
|
||||
clientSecretConfiguredPlaceholder: '********',
|
||||
clientSecretConfiguredHint: '密钥已配置,留空以保留当前值。',
|
||||
redirectUrl: '回调地址(Redirect URL)',
|
||||
redirectUrlPlaceholder: 'https://your-domain.com/api/v1/auth/oauth/linuxdo/callback',
|
||||
redirectUrlHint: '需与 Connect.Linux.Do 中配置的回调地址一致(必须是 http(s) 完整 URL)'
|
||||
},
|
||||
defaults: {
|
||||
title: '用户默认设置',
|
||||
description: '新用户的默认值',
|
||||
|
||||
@@ -261,6 +261,91 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- LinuxDo Connect OAuth Login -->
|
||||
<div class="card">
|
||||
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
||||
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
{{ t('admin.settings.linuxdo.title') }}
|
||||
</h2>
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.settings.linuxdo.description') }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="space-y-5 p-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<label class="font-medium text-gray-900 dark:text-white">{{
|
||||
t('admin.settings.linuxdo.enable')
|
||||
}}</label>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.settings.linuxdo.enableHint') }}
|
||||
</p>
|
||||
</div>
|
||||
<Toggle v-model="form.linuxdo_connect_enabled" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="form.linuxdo_connect_enabled"
|
||||
class="border-t border-gray-100 pt-4 dark:border-dark-700"
|
||||
>
|
||||
<div class="grid grid-cols-1 gap-6">
|
||||
<div>
|
||||
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ t('admin.settings.linuxdo.clientId') }}
|
||||
</label>
|
||||
<input
|
||||
v-model="form.linuxdo_connect_client_id"
|
||||
type="text"
|
||||
class="input font-mono text-sm"
|
||||
:placeholder="t('admin.settings.linuxdo.clientIdPlaceholder')"
|
||||
/>
|
||||
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.settings.linuxdo.clientIdHint') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ t('admin.settings.linuxdo.clientSecret') }}
|
||||
</label>
|
||||
<input
|
||||
v-model="form.linuxdo_connect_client_secret"
|
||||
type="password"
|
||||
class="input font-mono text-sm"
|
||||
:placeholder="
|
||||
form.linuxdo_connect_client_secret_configured
|
||||
? t('admin.settings.linuxdo.clientSecretConfiguredPlaceholder')
|
||||
: t('admin.settings.linuxdo.clientSecretPlaceholder')
|
||||
"
|
||||
/>
|
||||
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{
|
||||
form.linuxdo_connect_client_secret_configured
|
||||
? t('admin.settings.linuxdo.clientSecretConfiguredHint')
|
||||
: t('admin.settings.linuxdo.clientSecretHint')
|
||||
}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ t('admin.settings.linuxdo.redirectUrl') }}
|
||||
</label>
|
||||
<input
|
||||
v-model="form.linuxdo_connect_redirect_url"
|
||||
type="url"
|
||||
class="input font-mono text-sm"
|
||||
:placeholder="t('admin.settings.linuxdo.redirectUrlPlaceholder')"
|
||||
/>
|
||||
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.settings.linuxdo.redirectUrlHint') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Default Settings -->
|
||||
<div class="card">
|
||||
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
||||
@@ -721,6 +806,7 @@ const newAdminApiKey = ref('')
|
||||
type SettingsForm = SystemSettings & {
|
||||
smtp_password: string
|
||||
turnstile_secret_key: string
|
||||
linuxdo_connect_client_secret: string
|
||||
}
|
||||
|
||||
const form = reactive<SettingsForm>({
|
||||
@@ -747,6 +833,12 @@ const form = reactive<SettingsForm>({
|
||||
turnstile_site_key: '',
|
||||
turnstile_secret_key: '',
|
||||
turnstile_secret_key_configured: false,
|
||||
// LinuxDo Connect OAuth
|
||||
linuxdo_connect_enabled: false,
|
||||
linuxdo_connect_client_id: '',
|
||||
linuxdo_connect_client_secret: '',
|
||||
linuxdo_connect_client_secret_configured: false,
|
||||
linuxdo_connect_redirect_url: '',
|
||||
// Identity patch (Claude -> Gemini)
|
||||
enable_identity_patch: true,
|
||||
identity_patch_prompt: ''
|
||||
@@ -797,6 +889,7 @@ async function loadSettings() {
|
||||
Object.assign(form, settings)
|
||||
form.smtp_password = ''
|
||||
form.turnstile_secret_key = ''
|
||||
form.linuxdo_connect_client_secret = ''
|
||||
} catch (error: any) {
|
||||
appStore.showError(
|
||||
t('admin.settings.failedToLoad') + ': ' + (error.message || t('common.unknownError'))
|
||||
@@ -829,12 +922,17 @@ async function saveSettings() {
|
||||
smtp_use_tls: form.smtp_use_tls,
|
||||
turnstile_enabled: form.turnstile_enabled,
|
||||
turnstile_site_key: form.turnstile_site_key,
|
||||
turnstile_secret_key: form.turnstile_secret_key || undefined
|
||||
turnstile_secret_key: form.turnstile_secret_key || undefined,
|
||||
linuxdo_connect_enabled: form.linuxdo_connect_enabled,
|
||||
linuxdo_connect_client_id: form.linuxdo_connect_client_id,
|
||||
linuxdo_connect_client_secret: form.linuxdo_connect_client_secret || undefined,
|
||||
linuxdo_connect_redirect_url: form.linuxdo_connect_redirect_url
|
||||
}
|
||||
const updated = await adminAPI.settings.updateSettings(payload)
|
||||
Object.assign(form, updated)
|
||||
form.smtp_password = ''
|
||||
form.turnstile_secret_key = ''
|
||||
form.linuxdo_connect_client_secret = ''
|
||||
// Refresh cached public settings so sidebar/header update immediately
|
||||
await appStore.fetchPublicSettings(true)
|
||||
appStore.showSuccess(t('admin.settings.settingsSaved'))
|
||||
|
||||
Reference in New Issue
Block a user