From 33b6edc01f9d47953a1474dcb2b597dc93cfcffd Mon Sep 17 00:00:00 2001 From: fit2cloud-chenyw Date: Tue, 18 Nov 2025 09:57:58 +0800 Subject: [PATCH] feat(X-Pack): Add OAuth2 authentication mechanism --- frontend/auto-imports.d.ts | 6 + frontend/src/i18n/en.json | 12 +- frontend/src/i18n/ko-KR.json | 12 +- frontend/src/i18n/zh-CN.json | 12 +- frontend/src/utils/utils.ts | 5 + frontend/src/views/login/xpack/Handler.vue | 52 ++++- frontend/src/views/login/xpack/Oauth2.vue | 52 +++++ .../system/authentication/Oauth2Editor.vue | 206 ++++++++++++------ .../src/views/system/authentication/index.vue | 4 +- 9 files changed, 286 insertions(+), 75 deletions(-) create mode 100644 frontend/src/views/login/xpack/Oauth2.vue diff --git a/frontend/auto-imports.d.ts b/frontend/auto-imports.d.ts index 5583f547..8970eb9d 100644 --- a/frontend/auto-imports.d.ts +++ b/frontend/auto-imports.d.ts @@ -7,7 +7,13 @@ export {} declare global { const ElButton: typeof import('element-plus-secondary/es')['ElButton'] + const ElCheckbox: typeof import('element-plus-secondary/es')['ElCheckbox'] + const ElDatePicker: typeof import('element-plus-secondary/es')['ElDatePicker'] + const ElInput: typeof import('element-plus-secondary/es')['ElInput'] const ElMessage: typeof import('element-plus-secondary/es')['ElMessage'] const ElMessageBox: typeof import('element-plus-secondary/es')['ElMessageBox'] + const ElRadio: typeof import('element-plus-secondary/es')['ElRadio'] + const ElRadioGroup: typeof import('element-plus-secondary/es')['ElRadioGroup'] + const ElSelect: typeof import('element-plus-secondary/es')['ElSelect'] const LicenseGenerator: any } diff --git a/frontend/src/i18n/en.json b/frontend/src/i18n/en.json index 1d1ad17e..2fa7f744 100644 --- a/frontend/src/i18n/en.json +++ b/frontend/src/i18n/en.json @@ -704,7 +704,17 @@ "field_mapping": "User Attribute Mapping", "field_mapping_placeholder": "Example: {'{'}\"account\": \"saml2Account\", \"name\": \"saml2Name\", \"email\": \"email\"{'}'}", "incorrect_please_re_enter": "Incorrect format, please re-enter", - "in_json_format": "Please enter JSON format" + "in_json_format": "Please enter JSON format", + "authorize_url": "Authorization URL", + "client_id": "Client ID", + "client_secret": "Client Secret", + "redirect_url": "Redirect URL", + "oauth2_settings": "OAuth2 Settings", + "scope": "Scope", + "userinfo_url": "User Info URL", + "token_url": "Token URL", + "revoke_url": "Revocation URL", + "oauth2_field_mapping_placeholder": "Example: {'{'}\"account\": \"OAuth2Account\", \"name\": \"OAuth2Name\", \"email\": \"email\"{'}'}" }, "login": { "default_login": "Default", diff --git a/frontend/src/i18n/ko-KR.json b/frontend/src/i18n/ko-KR.json index 286dcaaf..4c410846 100644 --- a/frontend/src/i18n/ko-KR.json +++ b/frontend/src/i18n/ko-KR.json @@ -704,7 +704,17 @@ "field_mapping": "사용자 속성 매핑", "field_mapping_placeholder": "예: {'{'}\"account\": \"saml2Account\", \"name\": \"saml2Name\", \"email\": \"email\"{'}'}", "incorrect_please_re_enter": "형식이 잘못되었습니다. 다시 입력해 주세요", - "in_json_format": "JSON 형식으로 입력해 주세요" + "in_json_format": "JSON 형식으로 입력해 주세요", + "authorize_url": "인증 URL", + "client_id": "클라이언트 ID", + "client_secret": "클라이언트 시크릿", + "redirect_url": "리디렉션 URL", + "oauth2_settings": "OAuth2 설정", + "scope": "권한 범위", + "userinfo_url": "사용자 정보 URL", + "token_url": "토큰 URL", + "revoke_url": "취소 URL", + "oauth2_field_mapping_placeholder": "예: {'{'}\"account\": \"OAuth2Account\", \"name\": \"OAuth2Name\", \"email\": \"email\"{'}'}" }, "login": { "default_login": "기본값", diff --git a/frontend/src/i18n/zh-CN.json b/frontend/src/i18n/zh-CN.json index b6e8c301..035e0a89 100644 --- a/frontend/src/i18n/zh-CN.json +++ b/frontend/src/i18n/zh-CN.json @@ -704,7 +704,17 @@ "field_mapping": "用户属性映射", "field_mapping_placeholder": "例如:{'{'}\"account\": \"saml2Account\", \"name\": \"saml2Name\", \"email\": \"email\"{'}'}", "incorrect_please_re_enter": "格式错误,请重新填写", - "in_json_format": "请输入json格式" + "in_json_format": "请输入json格式", + "authorize_url": "授权地址", + "client_id": "客户端 ID", + "client_secret": "客户端密钥", + "redirect_url": "回调地址", + "oauth2_settings": "OAuth2 设置", + "scope": "授权范围", + "userinfo_url": "用户信息地址", + "token_url": "令牌地址", + "revoke_url": "撤销地址", + "oauth2_field_mapping_placeholder": "例如:{'{'}\"account\": \"oauth2Account\", \"name\": \"oauth2Name\", \"email\": \"email\"{'}'}" }, "login": { "default_login": "默认", diff --git a/frontend/src/utils/utils.ts b/frontend/src/utils/utils.ts index 2b378326..3a18c5ba 100644 --- a/frontend/src/utils/utils.ts +++ b/frontend/src/utils/utils.ts @@ -213,6 +213,11 @@ export const getQueryString = (name: string) => { return null } +export const getUrlParams = () => { + const urlParams = new URLSearchParams(window.location.search) as any + return Object.fromEntries(urlParams) +} + export const isLarkPlatform = () => { return !!getQueryString('state') && !!getQueryString('code') } diff --git a/frontend/src/views/login/xpack/Handler.vue b/frontend/src/views/login/xpack/Handler.vue index 51f3ddaa..62396983 100644 --- a/frontend/src/views/login/xpack/Handler.vue +++ b/frontend/src/views/login/xpack/Handler.vue @@ -20,8 +20,8 @@ :ldap="loginCategory.ldap" @status-change="qrStatusChange" /> - - --> + --> + @@ -38,13 +38,14 @@ import Oidc from './Oidc.vue' import Oauth2 from './Oauth2.vue' import Saml2 from './Saml2.vue' */ import Cas from './Cas.vue' +import Oauth2 from './Oauth2.vue' // import QrTab from './QrTab.vue' import { request } from '@/utils/request' import { useCache } from '@/utils/useCache' import router from '@/router' import { useUserStore } from '@/stores/user.ts' -import { getQueryString, isPlatformClient } from '@/utils/utils' +import { getQueryString, getUrlParams, isPlatformClient } from '@/utils/utils' import { loadClient, type LoginCategory } from './PlatformClient' // import MfaStep from './MfaStep.vue' // import { logoutHandler } from '@/utils/logout' @@ -150,7 +151,10 @@ const switcherCategory = (param: Categoryparam) => { } const nextPage = curOrigin + pathname + proxy + curLocation if (category === 'oauth2') { - oauth2Handler?.value?.toLoginPage() + request.get('/system/authentication/login/4').then((res: any) => { + window.location.href = res + window.open(res, '_self') + }) return } if (category === 'saml2') { @@ -176,9 +180,12 @@ const getCurLocation = () => { } const casLogin = () => { + const urlParams = getUrlParams() const ticket = getQueryString('ticket') + /* request + .get('/system/authentication/sso/cas?ticket=' + ticket) */ request - .get('/system/authentication/sso/cas?ticket=' + ticket) + .post('/system/authentication/sso/1', urlParams) .then((res: any) => { const token = res.access_token if (token && isPlatformClient()) { @@ -207,6 +214,39 @@ const casLogin = () => { }, 1500) }) } +const oauth2Login = () => { + const urlParams = getUrlParams() + request + .post('/system/authentication/sso/4', urlParams) + .then((res: any) => { + const token = res.access_token + const id_token = res.id_token + if (token && isPlatformClient()) { + wsCache.set('de-platform-client', true) + } + userStore.setToken(token) + userStore.setExp(res.exp) + userStore.setTime(Date.now()) + userStore.setPlatformInfo({ + flag: 'oauth2', + data: id_token, + origin: 4, + }) + const queryRedirectPath = getCurLocation() + router.push({ path: queryRedirectPath }) + }) + .catch((e: any) => { + userStore.setToken('') + setTimeout(() => { + // logoutHandler(true, true) + platformLoginMsg.value = e?.message || e + setTimeout(() => { + window.location.href = + window.location.origin + window.location.pathname + window.location.hash + }, 2000) + }, 1500) + }) +} /* const platformLogin = (origin: number) => { const url = '/system/authentication/sso/cas' request @@ -384,6 +424,8 @@ onMounted(() => { if (state?.includes('cas') && getQueryString('ticket')) { // platformLogin(1) casLogin() + } else if (state?.includes('oauth2')) { + oauth2Login() } else { updateLoading(false) } diff --git a/frontend/src/views/login/xpack/Oauth2.vue b/frontend/src/views/login/xpack/Oauth2.vue new file mode 100644 index 00000000..12219176 --- /dev/null +++ b/frontend/src/views/login/xpack/Oauth2.vue @@ -0,0 +1,52 @@ + + + + diff --git a/frontend/src/views/system/authentication/Oauth2Editor.vue b/frontend/src/views/system/authentication/Oauth2Editor.vue index 573ecfd8..71e38895 100644 --- a/frontend/src/views/system/authentication/Oauth2Editor.vue +++ b/frontend/src/views/system/authentication/Oauth2Editor.vue @@ -1,36 +1,71 @@