feat(gateway): 添加 Claude Code 客户端最低版本检查功能
- 通过 User-Agent 识别 Claude Code 客户端并提取版本号 - 在网关层验证客户端版本是否满足管理员配置的最低要求 - 在管理后台提供版本要求配置选项(英文/中文双语) - 实现原子缓存 + singleflight 防止并发问题和 thundering herd - 使用 context.WithoutCancel 隔离 DB 查询,避免客户端断连影响缓存 - 双 TTL 策略:60s 正常、5s 错误恢复,保证性能与可用性 - 仅检查 Claude Code 客户端,其他客户端不受影响 - 添加完整单元测试覆盖版本提取、比对、上下文操作
This commit is contained in:
@@ -67,6 +67,9 @@ export interface SystemSettings {
|
||||
ops_realtime_monitoring_enabled: boolean
|
||||
ops_query_mode_default: 'auto' | 'raw' | 'preagg' | string
|
||||
ops_metrics_interval_seconds: number
|
||||
|
||||
// Claude Code version check
|
||||
min_claude_code_version: string
|
||||
}
|
||||
|
||||
export interface UpdateSettingsRequest {
|
||||
@@ -114,6 +117,7 @@ export interface UpdateSettingsRequest {
|
||||
ops_realtime_monitoring_enabled?: boolean
|
||||
ops_query_mode_default?: 'auto' | 'raw' | 'preagg' | string
|
||||
ops_metrics_interval_seconds?: number
|
||||
min_claude_code_version?: string
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3548,6 +3548,14 @@ export default {
|
||||
defaultConcurrency: 'Default Concurrency',
|
||||
defaultConcurrencyHint: 'Maximum concurrent requests for new users'
|
||||
},
|
||||
claudeCode: {
|
||||
title: 'Claude Code Settings',
|
||||
description: 'Control Claude Code client access requirements',
|
||||
minVersion: 'Minimum Version',
|
||||
minVersionPlaceholder: 'e.g. 2.1.63',
|
||||
minVersionHint:
|
||||
'Reject Claude Code clients below this version (semver format). Leave empty to disable version check.'
|
||||
},
|
||||
site: {
|
||||
title: 'Site Settings',
|
||||
description: 'Customize site branding',
|
||||
|
||||
@@ -3718,6 +3718,13 @@ export default {
|
||||
defaultConcurrency: '默认并发数',
|
||||
defaultConcurrencyHint: '新用户的最大并发请求数'
|
||||
},
|
||||
claudeCode: {
|
||||
title: 'Claude Code 设置',
|
||||
description: '控制 Claude Code 客户端访问要求',
|
||||
minVersion: '最低版本号',
|
||||
minVersionPlaceholder: '例如 2.1.63',
|
||||
minVersionHint: '拒绝低于此版本的 Claude Code 客户端请求(semver 格式)。留空则不检查版本。'
|
||||
},
|
||||
site: {
|
||||
title: '站点设置',
|
||||
description: '自定义站点品牌',
|
||||
|
||||
@@ -616,6 +616,35 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Claude Code Settings -->
|
||||
<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.claudeCode.title') }}
|
||||
</h2>
|
||||
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.settings.claudeCode.description') }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="p-6">
|
||||
<div>
|
||||
<label class="mb-2 block text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||
{{ t('admin.settings.claudeCode.minVersion') }}
|
||||
</label>
|
||||
<input
|
||||
v-model="form.min_claude_code_version"
|
||||
type="text"
|
||||
class="input max-w-xs font-mono text-sm"
|
||||
:placeholder="t('admin.settings.claudeCode.minVersionPlaceholder')"
|
||||
pattern="\d+\.\d+\.\d+"
|
||||
/>
|
||||
<p class="mt-1.5 text-xs text-gray-500 dark:text-gray-400">
|
||||
{{ t('admin.settings.claudeCode.minVersionHint') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Site Settings -->
|
||||
<div class="card">
|
||||
<div class="border-b border-gray-100 px-6 py-4 dark:border-dark-700">
|
||||
@@ -1203,7 +1232,9 @@ const form = reactive<SettingsForm>({
|
||||
ops_monitoring_enabled: true,
|
||||
ops_realtime_monitoring_enabled: true,
|
||||
ops_query_mode_default: 'auto',
|
||||
ops_metrics_interval_seconds: 60
|
||||
ops_metrics_interval_seconds: 60,
|
||||
// Claude Code version check
|
||||
min_claude_code_version: ''
|
||||
})
|
||||
|
||||
// LinuxDo OAuth redirect URL suggestion
|
||||
@@ -1320,7 +1351,8 @@ async function saveSettings() {
|
||||
fallback_model_gemini: form.fallback_model_gemini,
|
||||
fallback_model_antigravity: form.fallback_model_antigravity,
|
||||
enable_identity_patch: form.enable_identity_patch,
|
||||
identity_patch_prompt: form.identity_patch_prompt
|
||||
identity_patch_prompt: form.identity_patch_prompt,
|
||||
min_claude_code_version: form.min_claude_code_version
|
||||
}
|
||||
const updated = await adminAPI.settings.updateSettings(payload)
|
||||
Object.assign(form, updated)
|
||||
|
||||
Reference in New Issue
Block a user