Add user API key IP whitelist UI

This commit is contained in:
RWDai
2026-05-18 20:48:21 +08:00
parent 2a3593d9c5
commit 460cd63d3a
2 changed files with 47 additions and 4 deletions
+44 -2
View File
@@ -111,8 +111,11 @@
>
{{ apiKey.name }}
</div>
<div class="text-xs text-muted-foreground mt-0.5">
创建于 {{ formatDate(apiKey.created_at) }}
<div class="text-xs text-muted-foreground mt-0.5">
创建于 {{ formatDate(apiKey.created_at) }}
</div>
<div class="text-xs text-muted-foreground mt-0.5 truncate">
IP 白名单:{{ formatAllowedIps(apiKey.allowed_ips) }}
</div>
</div>
</TableCell>
@@ -355,6 +358,9 @@
{{ formatRateLimitSimple(apiKey.rate_limit) }}
</span>
</div>
<div class="text-xs text-muted-foreground truncate">
IP 白名单:{{ formatAllowedIps(apiKey.allowed_ips) }}
</div>
</div>
</div>
</Card>
@@ -451,6 +457,23 @@
</p>
</div>
<div class="space-y-2">
<Label
for="key-allowed-ips"
class="text-sm font-semibold"
>IP 白名单</Label>
<Input
id="key-allowed-ips"
v-model="newKeyAllowedIpsText"
placeholder="例如:203.0.113.10, 10.0.0.0/24"
class="h-11 border-border/60"
autocomplete="off"
/>
<p class="text-xs text-muted-foreground">
留空表示不限制来源 IP;支持单个 IP 或 CIDR,多个值用英文逗号分隔
</p>
</div>
<div class="rounded-lg border border-border/60 bg-muted/30 p-4">
<div class="flex items-center justify-between gap-4">
<div>
@@ -779,6 +802,7 @@ const showInstallDialog = ref(false)
const newKeyName = ref('')
const newKeyRateLimit = ref<number | undefined>(undefined)
const newKeyConcurrentLimit = ref<number | undefined>(undefined)
const newKeyAllowedIpsText = ref('')
const keyRedactionMode = ref<'inherit' | 'custom'>('inherit')
const newKeyRedactionEnabled = ref(false)
const newKeyRedactionInjectNotice = ref(true)
@@ -867,6 +891,7 @@ function openEditApiKeyDialog(apiKey: ApiKey) {
newKeyName.value = apiKey.name || ''
newKeyRateLimit.value = apiKey.rate_limit ?? undefined
newKeyConcurrentLimit.value = apiKey.concurrent_limit ?? undefined
newKeyAllowedIpsText.value = apiKey.allowed_ips?.join(', ') ?? ''
keyRedactionMode.value = hasRedactionFeature ? 'custom' : 'inherit'
newKeyRedactionEnabled.value = redactionFeature.enabled
newKeyRedactionInjectNotice.value = redactionFeature.inject_model_instruction
@@ -878,6 +903,7 @@ function openCreateApiKeyDialog() {
newKeyName.value = ''
newKeyRateLimit.value = undefined
newKeyConcurrentLimit.value = undefined
newKeyAllowedIpsText.value = ''
keyRedactionMode.value = 'inherit'
newKeyRedactionEnabled.value = false
newKeyRedactionInjectNotice.value = true
@@ -957,6 +983,7 @@ function closeApiKeyDialog() {
newKeyName.value = ''
newKeyRateLimit.value = undefined
newKeyConcurrentLimit.value = undefined
newKeyAllowedIpsText.value = ''
keyRedactionMode.value = 'inherit'
newKeyRedactionEnabled.value = false
newKeyRedactionInjectNotice.value = true
@@ -970,12 +997,14 @@ async function saveApiKey() {
creating.value = true
try {
const allowedIps = parseAllowedIpsInput(newKeyAllowedIpsText.value)
const isCreatingFirstApiKey = !editingApiKey.value && apiKeys.value.length === 0
if (editingApiKey.value) {
await meApi.updateApiKey(editingApiKey.value.id, {
name: newKeyName.value,
rate_limit: newKeyRateLimit.value ?? 0,
concurrent_limit: newKeyConcurrentLimit.value,
allowed_ips: allowedIps,
feature_settings: keyRedactionMode.value === 'custom'
? mergeChatPiiRedactionFeatureSettings(editingApiKey.value.feature_settings, {
enabled: newKeyRedactionEnabled.value,
@@ -989,6 +1018,7 @@ async function saveApiKey() {
name: newKeyName.value,
rate_limit: newKeyRateLimit.value ?? 0,
concurrent_limit: newKeyConcurrentLimit.value,
allowed_ips: allowedIps,
...(keyRedactionMode.value === 'custom'
? {
feature_settings: mergeChatPiiRedactionFeatureSettings(null, {
@@ -1118,6 +1148,18 @@ function formatConcurrentLimitSimple(concurrentLimit?: number | null): string {
return `${concurrentLimit} 并发`
}
function formatAllowedIps(allowedIps?: string[] | null): string {
return allowedIps && allowedIps.length > 0 ? allowedIps.join(', ') : '不限制'
}
function parseAllowedIpsInput(value: string): string[] | null {
const items = value
.split(',')
.map((item) => item.trim())
.filter(Boolean)
return items.length > 0 ? items : null
}
function formatDate(dateString?: string | null): string {
if (!dateString) return '未知'
const date = new Date(dateString)