From d239d405d7db83d326c3ce00839ac5b8b00f1496 Mon Sep 17 00:00:00 2001 From: fit2cloud-chenyw Date: Tue, 2 Dec 2025 15:34:17 +0800 Subject: [PATCH] perf: i18n Optimization for Third-Party Authentication Validation --- backend/locales/en.json | 3 +++ backend/locales/ko-KR.json | 3 +++ backend/locales/zh-CN.json | 3 +++ frontend/src/i18n/en.json | 1 + frontend/src/i18n/ko-KR.json | 1 + frontend/src/i18n/zh-CN.json | 1 + frontend/src/utils/utils.ts | 8 ++++++++ .../views/system/authentication/CasEditor.vue | 14 ++++++++++++-- .../views/system/authentication/Oauth2Editor.vue | 15 +++++++++++++-- .../views/system/authentication/OidcEditor.vue | 15 +++++++++++++-- .../src/views/system/authentication/index.vue | 16 +++++++--------- 11 files changed, 65 insertions(+), 15 deletions(-) diff --git a/backend/locales/en.json b/backend/locales/en.json index c43d4fb8..88cfa19d 100644 --- a/backend/locales/en.json +++ b/backend/locales/en.json @@ -114,5 +114,8 @@ }, "i18n_excel_import": { "col_num_not_match": "Number of columns in Excel does not match" + }, + "i18n_authentication": { + "record_not_exist": "{msg} record does not exist. Please save it first!" } } \ No newline at end of file diff --git a/backend/locales/ko-KR.json b/backend/locales/ko-KR.json index 87d883f9..084e547e 100644 --- a/backend/locales/ko-KR.json +++ b/backend/locales/ko-KR.json @@ -114,5 +114,8 @@ }, "i18n_excel_import": { "col_num_not_match": "Excel 열 개수가 일치하지 않습니다" + }, + "i18n_authentication": { + "record_not_exist": "{msg} 기록이 존재하지 않습니다. 먼저 저장해 주세요!" } } \ No newline at end of file diff --git a/backend/locales/zh-CN.json b/backend/locales/zh-CN.json index 3393f402..b0c17ae3 100644 --- a/backend/locales/zh-CN.json +++ b/backend/locales/zh-CN.json @@ -114,5 +114,8 @@ }, "i18n_excel_import": { "col_num_not_match": "EXCEL列数量不匹配" + }, + "i18n_authentication": { + "record_not_exist": "{msg} 记录不存在,请先保存!" } } \ No newline at end of file diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index e36d0874..191e1ecf 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -732,6 +732,7 @@ "valid": "Valid", "cas_settings": "CAS Settings", "callback_domain_name": "Callback Domain", + "callback_domain_name_error": "Callback URL must match the current access domain", "field_mapping": "User Attribute Mapping", "field_mapping_placeholder": "Example: {'{'}\"account\": \"saml2Account\", \"name\": \"saml2Name\", \"email\": \"email\"{'}'}", "incorrect_please_re_enter": "Incorrect format, please re-enter", diff --git a/frontend/src/i18n/ko-KR.json b/frontend/src/i18n/ko-KR.json index 485b5b57..109c085d 100644 --- a/frontend/src/i18n/ko-KR.json +++ b/frontend/src/i18n/ko-KR.json @@ -732,6 +732,7 @@ "valid": "유효함", "cas_settings": "CAS 설정", "callback_domain_name": "콜백 도메인", + "callback_domain_name_error": "콜백 URL은 현재 접속 도메인과 일치해야 합니다", "field_mapping": "사용자 속성 매핑", "field_mapping_placeholder": "예: {'{'}\"account\": \"saml2Account\", \"name\": \"saml2Name\", \"email\": \"email\"{'}'}", "incorrect_please_re_enter": "형식이 잘못되었습니다. 다시 입력해 주세요", diff --git a/frontend/src/i18n/zh-CN.json b/frontend/src/i18n/zh-CN.json index 31c8f233..7e0a6b80 100644 --- a/frontend/src/i18n/zh-CN.json +++ b/frontend/src/i18n/zh-CN.json @@ -732,6 +732,7 @@ "valid": "有效", "cas_settings": "CAS 设置", "callback_domain_name": "回调地址", + "callback_domain_name_error": "回调地址必须是当前访问域名", "field_mapping": "用户属性映射", "field_mapping_placeholder": "例如:{'{'}\"account\": \"saml2Account\", \"name\": \"saml2Name\", \"email\": \"email\"{'}'}", "incorrect_please_re_enter": "格式错误,请重新填写", diff --git a/frontend/src/utils/utils.ts b/frontend/src/utils/utils.ts index 3a18c5ba..f31e25d6 100644 --- a/frontend/src/utils/utils.ts +++ b/frontend/src/utils/utils.ts @@ -255,3 +255,11 @@ export function isMobile() { ) && !isTablet() ) } + +export const getSQLBotAddr = (portEnd?: boolean) => { + const addr = location.origin + location.pathname + if (!portEnd || !addr.endsWith('/')) { + return addr + } + return addr.substring(0, addr.length - 1) +} diff --git a/frontend/src/views/system/authentication/CasEditor.vue b/frontend/src/views/system/authentication/CasEditor.vue index 4ffe0613..91a59289 100644 --- a/frontend/src/views/system/authentication/CasEditor.vue +++ b/frontend/src/views/system/authentication/CasEditor.vue @@ -4,6 +4,7 @@ import { ElMessage, ElLoading } from 'element-plus-secondary' import { useI18n } from 'vue-i18n' import type { FormInstance, FormRules } from 'element-plus-secondary' import { request } from '@/utils/request' +import { getSQLBotAddr } from '@/utils/utils' const { t } = useI18n() const dialogVisible = ref(false) const loadingInstance = ref | null>(null) @@ -17,7 +18,7 @@ interface CasForm { const state = reactive({ form: reactive({ idpUri: '', - casCallbackDomain: '', + casCallbackDomain: getSQLBotAddr(), mapping: '', }), }) @@ -33,6 +34,15 @@ const validateUrl = (rule, value, callback) => { } // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error +const validateCbUrl = (rule, value, callback) => { + const addr = getSQLBotAddr() + if (value === addr || `${value}/` === addr) { + callback() + } + callback(new Error(t('authentication.callback_domain_name_error'))) +} +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-expect-error const validateMapping = (rule, value, callback) => { if (!value) { callback() @@ -76,7 +86,7 @@ const rule = reactive({ message: t('commons.input_limit', [10, 255]), trigger: 'blur', }, - { required: true, validator: validateUrl, trigger: 'blur' }, + { required: true, validator: validateCbUrl, trigger: 'blur' }, ], mapping: [{ required: false, validator: validateMapping, trigger: 'blur' }], }) diff --git a/frontend/src/views/system/authentication/Oauth2Editor.vue b/frontend/src/views/system/authentication/Oauth2Editor.vue index eeb5ff3e..39adc3df 100644 --- a/frontend/src/views/system/authentication/Oauth2Editor.vue +++ b/frontend/src/views/system/authentication/Oauth2Editor.vue @@ -11,6 +11,8 @@ import { ElSelect, } from 'element-plus-secondary' import { request } from '@/utils/request' +import { getSQLBotAddr } from '@/utils/utils' + const { t } = useI18n() const dialogVisible = ref(false) const loadingInstance = ref | null>(null) @@ -26,7 +28,7 @@ const state = reactive({ scope: '', client_id: '', client_secret: '', - redirect_url: '', + redirect_url: getSQLBotAddr(), token_auth_method: 'basic', userinfo_auth_method: 'header', logout_redirect_url: '', @@ -81,6 +83,15 @@ const validateUrl = (rule, value, callback) => { } // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error +const validateCbUrl = (rule, value, callback) => { + const addr = getSQLBotAddr() + if (value === addr || `${value}/` === addr) { + callback() + } + callback(new Error(t('authentication.callback_domain_name_error'))) +} +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-expect-error const validateMapping = (rule, value, callback) => { if (value === null || value === '') { callback() @@ -183,7 +194,7 @@ const rule = reactive({ message: t('commons.input_limit', [10, 255]), trigger: 'blur', }, - { required: true, validator: validateUrl, trigger: 'blur' }, + { required: true, validator: validateCbUrl, trigger: 'blur' }, ], mapping: [{ required: false, validator: validateMapping, trigger: 'blur' }], }) diff --git a/frontend/src/views/system/authentication/OidcEditor.vue b/frontend/src/views/system/authentication/OidcEditor.vue index 6adf7a20..7fbd5173 100644 --- a/frontend/src/views/system/authentication/OidcEditor.vue +++ b/frontend/src/views/system/authentication/OidcEditor.vue @@ -4,6 +4,8 @@ import { ElMessage, ElLoading } from 'element-plus-secondary' import { useI18n } from 'vue-i18n' import type { FormInstance, FormRules } from 'element-plus-secondary' import { request } from '@/utils/request' +import { getSQLBotAddr } from '@/utils/utils' + const { t } = useI18n() const dialogVisible = ref(false) const loadingInstance = ref | null>(null) @@ -15,7 +17,7 @@ const state = reactive({ client_id: '', client_secret: '', metadata_url: '', - redirect_uri: '', + redirect_uri: getSQLBotAddr(), realm: '', scope: '', mapping: '', @@ -45,6 +47,15 @@ const validateMapping = (rule, value, callback) => { } callback() } +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-expect-error +const validateCbUrl = (rule, value, callback) => { + const addr = getSQLBotAddr() + if (value === addr || `${value}/` === addr) { + callback() + } + callback(new Error(t('authentication.callback_domain_name_error'))) +} const rule = reactive({ client_id: [ { @@ -84,7 +95,7 @@ const rule = reactive({ message: t('commons.input_limit', [10, 255]), trigger: 'blur', }, - { required: true, validator: validateUrl, trigger: 'blur' }, + { required: true, validator: validateCbUrl, trigger: 'blur' }, ], metadata_url: [ { diff --git a/frontend/src/views/system/authentication/index.vue b/frontend/src/views/system/authentication/index.vue index d0349a2b..5a52a538 100644 --- a/frontend/src/views/system/authentication/index.vue +++ b/frontend/src/views/system/authentication/index.vue @@ -90,7 +90,13 @@ const init = (needLoading: boolean) => { .get(url) .then((res) => { if (res) { - infos.value = [...(res as CardInfo[])].filter((item) => item.name !== 'saml2') + const templateArray = ['ldap', 'oidc', 'cas', 'oauth2'] + const resultList = [...(res as CardInfo[])].filter((item) => item.name !== 'saml2') + let resultMap = {} as any + resultList.forEach((item: any) => { + resultMap[item.name] = item + }) + infos.value = templateArray.map((item: string) => resultMap[item]) showInfos.value = [...infos.value] } loading.value = false @@ -130,14 +136,6 @@ const editInfo = (item: CardInfo) => { } } const validate = (id: any) => { - if (!id) { - ElMessage.error( - `${t('ds.test_connection') + t('report.last_status_fail')}: ${t( - 'system.platform_information_first' - )}` - ) - return - } loading.value = true request .patch('/system/authentication/status', { type: id, name: '', config: '' })