From e25139b0009ef77477bc9c1503e7af4203226da9 Mon Sep 17 00:00:00 2001 From: wxg0103 <727495428@qq.com> Date: Mon, 21 Sep 2026 17:58:44 +0800 Subject: [PATCH] refactor: replace cors_config with cross_domain_list for improved CORS handling --- apps/chat/api/portal_api.py | 6 +++++- apps/portal/api/portal.py | 6 +++++- apps/portal/migrations/0001_initial.py | 10 ++++++++-- apps/portal/models/portal.py | 5 ++++- apps/portal/serializers/portal.py | 6 +++++- ui/src/api/API_README.md | 3 +-- ui/src/api/types/portal.ts | 7 +------ .../portal-setting/PortalSettingView.vue | 10 +++++----- .../components/ButtonPortalCorsSetting.vue | 5 +++-- 9 files changed, 37 insertions(+), 21 deletions(-) diff --git a/apps/chat/api/portal_api.py b/apps/chat/api/portal_api.py index db9b1d6fb03..f77137227cb 100644 --- a/apps/chat/api/portal_api.py +++ b/apps/chat/api/portal_api.py @@ -37,7 +37,11 @@ def get_request(): "enable_auth": {"type": "boolean", "description": "是否开启身份认证"}, "auth_config": {"type": "object", "description": "身份认证配置"}, "enable_cors": {"type": "boolean", "description": "是否开启跨域设置"}, - "cors_config": {"type": "object", "description": "跨域配置"}, + "cross_domain_list": { + "type": "array", + "items": {"type": "string"}, + "description": "跨域列表", + }, }, } } diff --git a/apps/portal/api/portal.py b/apps/portal/api/portal.py index 0728331a600..70ffa107062 100644 --- a/apps/portal/api/portal.py +++ b/apps/portal/api/portal.py @@ -37,7 +37,11 @@ def get_request(): "enable_auth": {"type": "boolean", "description": "是否开启身份认证"}, "auth_config": {"type": "object", "description": "身份认证配置"}, "enable_cors": {"type": "boolean", "description": "是否开启跨域设置"}, - "cors_config": {"type": "object", "description": "跨域配置"}, + "cross_domain_list": { + "type": "array", + "items": {"type": "string"}, + "description": "跨域列表", + }, }, } } diff --git a/apps/portal/migrations/0001_initial.py b/apps/portal/migrations/0001_initial.py index 4269916ad39..aca7fe4ec70 100644 --- a/apps/portal/migrations/0001_initial.py +++ b/apps/portal/migrations/0001_initial.py @@ -1,6 +1,7 @@ # Generated by Django 6.0.7 on 2026-08-03 06:20 import uuid_utils.compat +import django.contrib.postgres.fields from django.db import migrations, models @@ -16,7 +17,7 @@ def create_default_portal(apps, schema_editor): enable_auth=False, auth_config={}, enable_cors=False, - cors_config={}, + cross_domain_list=[], ) @@ -50,7 +51,12 @@ class Migration(migrations.Migration): ("enable_auth", models.BooleanField(default=False, verbose_name="是否开启身份认证")), ("auth_config", models.JSONField(blank=True, default=dict, verbose_name="身份认证配置")), ("enable_cors", models.BooleanField(default=False, verbose_name="是否开启跨域设置")), - ("cors_config", models.JSONField(blank=True, default=dict, verbose_name="跨域配置")), + ( + "cross_domain_list", + django.contrib.postgres.fields.ArrayField( + base_field=models.CharField(blank=True, max_length=512), default=list, verbose_name="跨域列表" + ), + ), ], options={ "db_table": "portal", diff --git a/apps/portal/models/portal.py b/apps/portal/models/portal.py index e7d42ecd538..dac64f7dd47 100644 --- a/apps/portal/models/portal.py +++ b/apps/portal/models/portal.py @@ -1,6 +1,7 @@ # coding=utf-8 import uuid_utils.compat as uuid +from django.contrib.postgres.fields import ArrayField from common.mixins.app_model_mixin import AppModelMixin from django.db import models @@ -32,7 +33,9 @@ class Portal(AppModelMixin): enable_cors = models.BooleanField(default=False, verbose_name="是否开启跨域设置") - cors_config = models.JSONField(default=dict, blank=True, verbose_name="跨域配置") + cross_domain_list = ArrayField( + verbose_name="跨域列表", base_field=models.CharField(max_length=512, blank=True), default=list + ) class Meta: db_table = "portal" diff --git a/apps/portal/serializers/portal.py b/apps/portal/serializers/portal.py index d5797024b35..1e1fbbb0448 100644 --- a/apps/portal/serializers/portal.py +++ b/apps/portal/serializers/portal.py @@ -55,7 +55,11 @@ class PortalSerializer(serializers.Serializer): enable_auth = serializers.BooleanField(required=False, label=_("enable auth"), help_text=_("enable auth")) auth_config = serializers.JSONField(required=False, label=_("auth config"), help_text=_("auth config")) enable_cors = serializers.BooleanField(required=False, label=_("enable cors"), help_text=_("enable cors")) - cors_config = serializers.JSONField(required=False, label=_("cors config"), help_text=_("cors config")) + cross_domain_list = serializers.ListSerializer( + required=False, + child=serializers.CharField(required=True, label=_("Cross-domain address")), + label=_("Cross-domain list"), + ) class Model(serializers.ModelSerializer): class Meta: diff --git a/ui/src/api/API_README.md b/ui/src/api/API_README.md index e5069812ed6..f8243b70525 100644 --- a/ui/src/api/API_README.md +++ b/ui/src/api/API_README.md @@ -64,8 +64,7 @@ src/api/ 公共类型维护在 `types/portal.ts`。JSON 用于访问开关和认证、跨域配置,门户名称与 Logo 使用 FormData;保存返回完整配置,页面以该返回值作为唯一数据来源。 认证配置保留未编辑字段,仅提交后端读取的 `login_value`、`max_attempts`、`failed_attempts`、 -`lock_time`;跨域配置写入 `cross_domain_list`(对齐后端 `ApplicationApiKey.cross_domain_list`), -并保留 `cors_config` 中的其他字段。 +`lock_time`;跨域地址直接提交后端 `Portal.cross_domain_list` 数组字段,不再维护 `cors_config`。 - 业务 API 先按 Admin 入口下的 `auth`、`workspace`、`system` 等一级业务域归类。Workspace 和 System 内部可继续按明确的功能域建立子目录,例如 `workspace/application/`、 diff --git a/ui/src/api/types/portal.ts b/ui/src/api/types/portal.ts index 9f5ca0e48ff..905382237be 100644 --- a/ui/src/api/types/portal.ts +++ b/ui/src/api/types/portal.ts @@ -7,11 +7,6 @@ export interface PortalAuthConfig extends Dict { lock_time?: number } -export interface PortalCorsConfig extends Dict { - /** 允许跨域访问的地址列表,对齐后端 cross_domain_list 字段。 */ - cross_domain_list?: string[] -} - export interface PortalSetting { id: string name: string @@ -23,7 +18,7 @@ export interface PortalSetting { enable_auth: boolean auth_config: PortalAuthConfig enable_cors: boolean - cors_config: PortalCorsConfig + cross_domain_list: string[] } export type PortalSettingPayload = Partial> diff --git a/ui/src/views/system/chat-management/portal-setting/PortalSettingView.vue b/ui/src/views/system/chat-management/portal-setting/PortalSettingView.vue index e8df9685e59..2db449aa1a2 100644 --- a/ui/src/views/system/chat-management/portal-setting/PortalSettingView.vue +++ b/ui/src/views/system/chat-management/portal-setting/PortalSettingView.vue @@ -29,7 +29,7 @@ const portalSetting = reactive({ lock_time: 10, }, enable_cors: false, - cors_config: {}, + cross_domain_list: [], }) const loading = ref(false) const saving = ref(false) @@ -75,9 +75,9 @@ function savePortalAuthSetting(payload: PortalSettingPayload) { return savePortalSetting(payload) } -/* 跨域地址保存:写入 cors_config 的 cross_domain_list,保留其余字段 */ +/* 跨域地址保存 */ function savePortalCorsSetting(origins: string[]) { - return savePortalSetting({ cors_config: { ...portalSetting.cors_config, cross_domain_list: origins } }) + return savePortalSetting({ cross_domain_list: origins }) } function handleOpenAuthSetting(enableAfterSave = false) { @@ -88,9 +88,9 @@ function handleOpenAuthSetting(enableAfterSave = false) { const authSettingButtonRef = useTemplateRef>('authSettingButtonRef') const portalCorsOrigins = computed({ - get: () => portalSetting.cors_config.cross_domain_list ?? [], + get: () => portalSetting.cross_domain_list ?? [], set: (origins: string[]) => { - portalSetting.cors_config = { ...portalSetting.cors_config, cross_domain_list: origins } + portalSetting.cross_domain_list = origins }, }) const previewName = computed(() => portalSetting.name) diff --git a/ui/src/views/system/chat-management/portal-setting/components/ButtonPortalCorsSetting.vue b/ui/src/views/system/chat-management/portal-setting/components/ButtonPortalCorsSetting.vue index 262fa3caa90..2e56facccc6 100644 --- a/ui/src/views/system/chat-management/portal-setting/components/ButtonPortalCorsSetting.vue +++ b/ui/src/views/system/chat-management/portal-setting/components/ButtonPortalCorsSetting.vue @@ -15,12 +15,13 @@ function handleOpenCorsSetting() { corsVisible.value = true } -/* 按行解析跨域地址,去掉行首尾空白与空行 */ +/* 按行解析跨域地址,去掉行首尾空白与空行后按顺序去重 */ function parseCorsOrigins(value: string) { - return value + const origins = value .split('\n') .map((origin) => origin.trim()) .filter(Boolean) + return [...new Set(origins)] } function handleSaveCorsSetting() {