feat: add authentication options for plugins including AuthEnabled, AuthUsername, and AuthPassword
All checks were successful
Build Multi-Platform Binaries / build-frontend (push) Successful in 3m27s
Build Multi-Platform Binaries / build-binaries (amd64, linux, client, true) (push) Successful in 5m51s
Build Multi-Platform Binaries / build-binaries (amd64, darwin, server, false) (push) Successful in 9m56s
Build Multi-Platform Binaries / build-binaries (amd64, linux, server, true) (push) Successful in 7m58s
Build Multi-Platform Binaries / build-binaries (amd64, windows, client, true) (push) Successful in 6m5s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, client, true) (push) Successful in 3m45s
Build Multi-Platform Binaries / build-binaries (amd64, windows, server, true) (push) Successful in 9m10s
Build Multi-Platform Binaries / build-binaries (arm, 7, linux, server, true) (push) Successful in 7m44s
Build Multi-Platform Binaries / build-binaries (arm64, linux, client, true) (push) Successful in 4m49s
Build Multi-Platform Binaries / build-binaries (arm64, darwin, server, false) (push) Successful in 10m19s
Build Multi-Platform Binaries / build-binaries (arm64, linux, server, true) (push) Successful in 7m35s
Build Multi-Platform Binaries / build-binaries (arm64, windows, server, false) (push) Successful in 10m2s

This commit is contained in:
2026-01-05 21:17:09 +08:00
parent c1f6e0bdcf
commit de206bf85a
7 changed files with 155 additions and 19 deletions

View File

@@ -49,8 +49,30 @@ export const disablePlugin = (name: string) => post(`/plugin/${name}/disable`)
// 扩展商店
export const getStorePlugins = () => get<{ plugins: StorePluginInfo[] }>('/store/plugins')
export const installStorePlugin = (pluginName: string, downloadUrl: string, signatureUrl: string, clientId: string, remotePort?: number, version?: string, configSchema?: ConfigField[]) =>
post('/store/install', { plugin_name: pluginName, version: version || '', download_url: downloadUrl, signature_url: signatureUrl, client_id: clientId, remote_port: remotePort || 0, config_schema: configSchema || [] })
export const installStorePlugin = (
pluginName: string,
downloadUrl: string,
signatureUrl: string,
clientId: string,
remotePort?: number,
version?: string,
configSchema?: ConfigField[],
authEnabled?: boolean,
authUsername?: string,
authPassword?: string
) =>
post('/store/install', {
plugin_name: pluginName,
version: version || '',
download_url: downloadUrl,
signature_url: signatureUrl,
client_id: clientId,
remote_port: remotePort || 0,
config_schema: configSchema || [],
auth_enabled: authEnabled || false,
auth_username: authUsername || '',
auth_password: authPassword || ''
})
// 客户端插件配置
export const getClientPluginConfig = (clientId: string, pluginName: string) =>

View File

@@ -88,6 +88,14 @@ const storePlugins = ref<StorePluginInfo[]>([])
const storeLoading = ref(false)
const storeInstalling = ref<string | null>(null) // 正在安装的插件名称
// 安装配置模态框
const showInstallConfigModal = ref(false)
const installPlugin = ref<StorePluginInfo | null>(null)
const installRemotePort = ref<number | null>(8080)
const installAuthEnabled = ref(false)
const installAuthUsername = ref('')
const installAuthPassword = ref('')
// 日志查看相关
const showLogViewer = ref(false)
@@ -111,11 +119,34 @@ const handleInstallStorePlugin = async (plugin: StorePluginInfo) => {
message.error('该插件没有下载地址')
return
}
// 打开配置模态框
installPlugin.value = plugin
installRemotePort.value = 8080
installAuthEnabled.value = false
installAuthUsername.value = ''
installAuthPassword.value = ''
showInstallConfigModal.value = true
}
storeInstalling.value = plugin.name
const confirmInstallPlugin = async () => {
if (!installPlugin.value) return
storeInstalling.value = installPlugin.value.name
try {
await installStorePlugin(plugin.name, plugin.download_url, plugin.signature_url || '', clientId, 8080, plugin.version, plugin.config_schema)
message.success(`已安装 ${plugin.name},可在配置中修改端口和其他设置`)
await installStorePlugin(
installPlugin.value.name,
installPlugin.value.download_url || '',
installPlugin.value.signature_url || '',
clientId,
installRemotePort.value || 8080,
installPlugin.value.version,
installPlugin.value.config_schema,
installAuthEnabled.value,
installAuthUsername.value,
installAuthPassword.value
)
message.success(`已安装 ${installPlugin.value.name}`)
showInstallConfigModal.value = false
showStoreModal.value = false
await loadClient()
} catch (e: any) {
@@ -748,6 +779,44 @@ const handleDeletePlugin = (plugin: ClientPlugin) => {
</template>
</n-modal>
<!-- 安装配置模态框 -->
<n-modal v-model:show="showInstallConfigModal" preset="card" title="安装配置" style="width: 450px;">
<n-space vertical :size="16">
<div v-if="installPlugin">
<p style="margin: 0 0 8px 0;"><strong>插件:</strong> {{ installPlugin.name }}</p>
<p style="margin: 0; color: #666;">{{ installPlugin.description }}</p>
</div>
<div>
<p style="margin: 0 0 8px 0; color: #666; font-size: 13px;">远程端口:</p>
<n-input-number
v-model:value="installRemotePort"
:min="1"
:max="65535"
placeholder="输入端口号"
style="width: 100%;"
/>
</div>
<div>
<n-space align="center" :size="8">
<n-switch v-model:value="installAuthEnabled" />
<span style="color: #666;">启用 HTTP Basic Auth</span>
</n-space>
</div>
<template v-if="installAuthEnabled">
<n-input v-model:value="installAuthUsername" placeholder="用户名" />
<n-input v-model:value="installAuthPassword" type="password" placeholder="密码" show-password-on="click" />
</template>
</n-space>
<template #footer>
<n-space justify="end">
<n-button @click="showInstallConfigModal = false">取消</n-button>
<n-button type="primary" :loading="!!storeInstalling" @click="confirmInstallPlugin">
安装
</n-button>
</n-space>
</template>
</n-modal>
<!-- 日志查看模态框 -->
<n-modal v-model:show="showLogViewer" preset="card" style="width: 900px; max-width: 95vw;">
<LogViewer :client-id="clientId" :visible="showLogViewer" @close="showLogViewer = false" />

View File

@@ -231,10 +231,18 @@ const showInstallModal = ref(false)
const selectedStorePlugin = ref<StorePluginInfo | null>(null)
const selectedClientId = ref('')
const installing = ref(false)
const installRemotePort = ref<number | null>(8080)
const installAuthEnabled = ref(false)
const installAuthUsername = ref('')
const installAuthPassword = ref('')
const openInstallModal = (plugin: StorePluginInfo) => {
selectedStorePlugin.value = plugin
selectedClientId.value = ''
installRemotePort.value = 8080
installAuthEnabled.value = false
installAuthUsername.value = ''
installAuthPassword.value = ''
showInstallModal.value = true
}
@@ -258,11 +266,14 @@ const handleInstallStorePlugin = async () => {
selectedStorePlugin.value.download_url,
selectedStorePlugin.value.signature_url,
selectedClientId.value,
8080, // 默认端口,可在配置中修改
installRemotePort.value || 8080,
selectedStorePlugin.value.version,
selectedStorePlugin.value.config_schema
selectedStorePlugin.value.config_schema,
installAuthEnabled.value,
installAuthUsername.value,
installAuthPassword.value
)
message.success(`已安装 ${selectedStorePlugin.value.name},可在客户端配置中修改端口和其他设置`)
message.success(`已安装 ${selectedStorePlugin.value.name}`)
showInstallModal.value = false
} catch (e: any) {
message.error(e.response?.data || '安装失败')
@@ -453,7 +464,7 @@ onMounted(() => {
-->
<!-- 安装商店插件模态框 -->
<n-modal v-model:show="showInstallModal" preset="card" title="安装插件" style="width: 400px;">
<n-modal v-model:show="showInstallModal" preset="card" title="安装插件" style="width: 450px;">
<n-space vertical :size="16">
<div v-if="selectedStorePlugin">
<p style="margin: 0 0 8px 0;"><strong>插件:</strong> {{ selectedStorePlugin.name }}</p>
@@ -464,7 +475,26 @@ onMounted(() => {
placeholder="选择要安装到的客户端"
:options="onlineClients.map(c => ({ label: c.nickname || c.id, value: c.id }))"
/>
<p style="margin: 0; color: #999; font-size: 12px;">安装后可在客户端详情页配置端口和其他设置</p>
<div>
<p style="margin: 0 0 8px 0; color: #666; font-size: 13px;">远程端口:</p>
<n-input-number
v-model:value="installRemotePort"
:min="1"
:max="65535"
placeholder="输入端口号"
style="width: 100%;"
/>
</div>
<div>
<n-space align="center" :size="8">
<n-switch v-model:value="installAuthEnabled" />
<span style="color: #666;">启用 HTTP Basic Auth</span>
</n-space>
</div>
<template v-if="installAuthEnabled">
<n-input v-model:value="installAuthUsername" placeholder="用户名" />
<n-input v-model:value="installAuthPassword" type="password" placeholder="密码" show-password-on="click" />
</template>
</n-space>
<template #footer>
<n-space justify="end">