mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-23 09:38:02 +00:00
feat(permissions): 服务权限从单选改为多选
- 将 API Key 的服务权限从单选改为多选,支持同时选择多个服务 - 移除"全部服务"选项,空数组表示允许访问全部服务 - 后端自动兼容旧格式('all' -> [], 'claude' -> ['claude']) - 前端 radio 改为 checkbox,更新账户选择器联动逻辑 修改文件: - apiKeyService.js: 添加 normalizePermissions/hasPermission 函数 - api.js, droidRoutes.js, openaiRoutes.js, unified.js, openaiGeminiRoutes.js, geminiHandlers.js: 使用新权限验证函数 - admin/apiKeys.js: 支持数组格式权限验证 - CreateApiKeyModal.vue, EditApiKeyModal.vue: UI 改为 checkbox 多选 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -412,55 +412,46 @@
|
||||
<label class="mb-3 block text-sm font-semibold text-gray-700 dark:text-gray-300"
|
||||
>服务权限</label
|
||||
>
|
||||
<div class="flex gap-4">
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<label class="flex cursor-pointer items-center">
|
||||
<input
|
||||
v-model="form.permissions"
|
||||
class="mr-2 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"
|
||||
type="radio"
|
||||
value="all"
|
||||
/>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">全部服务</span>
|
||||
</label>
|
||||
<label class="flex cursor-pointer items-center">
|
||||
<input
|
||||
v-model="form.permissions"
|
||||
class="mr-2 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"
|
||||
type="radio"
|
||||
class="mr-2 rounded text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"
|
||||
type="checkbox"
|
||||
value="claude"
|
||||
/>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">仅 Claude</span>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">Claude</span>
|
||||
</label>
|
||||
<label class="flex cursor-pointer items-center">
|
||||
<input
|
||||
v-model="form.permissions"
|
||||
class="mr-2 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"
|
||||
type="radio"
|
||||
class="mr-2 rounded text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"
|
||||
type="checkbox"
|
||||
value="gemini"
|
||||
/>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">仅 Gemini</span>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">Gemini</span>
|
||||
</label>
|
||||
<label class="flex cursor-pointer items-center">
|
||||
<input
|
||||
v-model="form.permissions"
|
||||
class="mr-2 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"
|
||||
type="radio"
|
||||
class="mr-2 rounded text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"
|
||||
type="checkbox"
|
||||
value="openai"
|
||||
/>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">仅 OpenAI</span>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">OpenAI</span>
|
||||
</label>
|
||||
<label class="flex cursor-pointer items-center">
|
||||
<input
|
||||
v-model="form.permissions"
|
||||
class="mr-2 text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"
|
||||
type="radio"
|
||||
class="mr-2 rounded text-blue-600 focus:ring-blue-500 dark:border-gray-600 dark:bg-gray-700"
|
||||
type="checkbox"
|
||||
value="droid"
|
||||
/>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">仅 Droid</span>
|
||||
<span class="text-sm text-gray-700 dark:text-gray-300">Droid</span>
|
||||
</label>
|
||||
</div>
|
||||
<p class="mt-2 text-xs text-gray-500 dark:text-gray-400">
|
||||
控制此 API Key 可以访问哪些服务
|
||||
不选择任何服务表示允许访问全部服务
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -495,7 +486,7 @@
|
||||
v-model="form.claudeAccountId"
|
||||
:accounts="localAccounts.claude"
|
||||
default-option-text="使用共享账号池"
|
||||
:disabled="form.permissions !== 'all' && form.permissions !== 'claude'"
|
||||
:disabled="form.permissions.length > 0 && !form.permissions.includes('claude')"
|
||||
:groups="localAccounts.claudeGroups"
|
||||
placeholder="请选择Claude账号"
|
||||
platform="claude"
|
||||
@@ -509,7 +500,7 @@
|
||||
v-model="form.geminiAccountId"
|
||||
:accounts="localAccounts.gemini"
|
||||
default-option-text="使用共享账号池"
|
||||
:disabled="form.permissions !== 'all' && form.permissions !== 'gemini'"
|
||||
:disabled="form.permissions.length > 0 && !form.permissions.includes('gemini')"
|
||||
:groups="localAccounts.geminiGroups"
|
||||
placeholder="请选择Gemini账号"
|
||||
platform="gemini"
|
||||
@@ -523,7 +514,7 @@
|
||||
v-model="form.openaiAccountId"
|
||||
:accounts="localAccounts.openai"
|
||||
default-option-text="使用共享账号池"
|
||||
:disabled="form.permissions !== 'all' && form.permissions !== 'openai'"
|
||||
:disabled="form.permissions.length > 0 && !form.permissions.includes('openai')"
|
||||
:groups="localAccounts.openaiGroups"
|
||||
placeholder="请选择OpenAI账号"
|
||||
platform="openai"
|
||||
@@ -537,7 +528,7 @@
|
||||
v-model="form.bedrockAccountId"
|
||||
:accounts="localAccounts.bedrock"
|
||||
default-option-text="使用共享账号池"
|
||||
:disabled="form.permissions !== 'all' && form.permissions !== 'openai'"
|
||||
:disabled="form.permissions.length > 0 && !form.permissions.includes('claude')"
|
||||
:groups="[]"
|
||||
placeholder="请选择Bedrock账号"
|
||||
platform="bedrock"
|
||||
@@ -551,7 +542,7 @@
|
||||
v-model="form.droidAccountId"
|
||||
:accounts="localAccounts.droid"
|
||||
default-option-text="使用共享账号池"
|
||||
:disabled="form.permissions !== 'all' && form.permissions !== 'droid'"
|
||||
:disabled="form.permissions.length > 0 && !form.permissions.includes('droid')"
|
||||
:groups="localAccounts.droidGroups"
|
||||
placeholder="请选择Droid账号"
|
||||
platform="droid"
|
||||
@@ -800,7 +791,7 @@ const form = reactive({
|
||||
dailyCostLimit: '',
|
||||
totalCostLimit: '',
|
||||
weeklyOpusCostLimit: '',
|
||||
permissions: 'all',
|
||||
permissions: [], // 数组格式,空数组表示全部服务
|
||||
claudeAccountId: '',
|
||||
geminiAccountId: '',
|
||||
openaiAccountId: '',
|
||||
@@ -1241,7 +1232,17 @@ onMounted(async () => {
|
||||
form.dailyCostLimit = props.apiKey.dailyCostLimit || ''
|
||||
form.totalCostLimit = props.apiKey.totalCostLimit || ''
|
||||
form.weeklyOpusCostLimit = props.apiKey.weeklyOpusCostLimit || ''
|
||||
form.permissions = props.apiKey.permissions || 'all'
|
||||
// 处理权限数据,兼容旧格式(字符串)和新格式(数组)
|
||||
const perms = props.apiKey.permissions
|
||||
if (Array.isArray(perms)) {
|
||||
form.permissions = perms
|
||||
} else if (perms === 'all' || !perms) {
|
||||
form.permissions = []
|
||||
} else if (typeof perms === 'string') {
|
||||
form.permissions = [perms]
|
||||
} else {
|
||||
form.permissions = []
|
||||
}
|
||||
// 处理 Claude 账号(区分 OAuth 和 Console)
|
||||
if (props.apiKey.claudeConsoleAccountId) {
|
||||
form.claudeAccountId = `console:${props.apiKey.claudeConsoleAccountId}`
|
||||
|
||||
Reference in New Issue
Block a user