From 7eb52770ad31d40c95a42a4648011be8a21b8962 Mon Sep 17 00:00:00 2001 From: NFish Date: Fri, 11 Apr 2025 16:41:20 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20remove=20sso=5Fenforced=5Ffor=5Fweb=5F?= =?UTF-8?q?protocol=E3=80=81enable=5Fweb=5Fsso=5Fswitch=5Fcomponent?= =?UTF-8?q?=E3=80=81sso=5Fenforced=5Ffor=5Fweb=20from=20systemFeatures=20,?= =?UTF-8?q?=20instead=20with=20webapp=5Fauth?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/(appDetailLayout)/[appId]/layout.tsx | 27 +++++------ .../[appId]/overview/cardView.tsx | 24 +--------- web/app/(shareLayout)/webapp-signin/page.tsx | 47 ++++++++++++------- web/app/components/app-sidebar/index.tsx | 2 +- .../app/app-access-control/index.tsx | 2 +- .../specific-groups-or-members.tsx | 2 +- web/models/app.ts | 4 +- web/service/apps.ts | 9 +--- web/service/base.ts | 4 +- web/types/feature.ts | 20 +++++--- 10 files changed, 66 insertions(+), 75 deletions(-) diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx index ab8c2b97db..f483e34001 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout.tsx @@ -20,7 +20,7 @@ import cn from '@/utils/classnames' import { useStore } from '@/app/components/app/store' import AppSideBar from '@/app/components/app-sidebar' import type { NavIcon } from '@/app/components/app-sidebar/navLink' -import { fetchAppDetail, fetchAppSSO } from '@/service/apps' +import { fetchAppDetail } from '@/service/apps' import { useAppContext } from '@/context/app-context' import Loading from '@/app/components/base/loading' import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints' @@ -32,6 +32,13 @@ export type IAppDetailLayoutProps = { params: { appId: string } } +type NavigationType = { + name: string + href: string + icon: NavIcon + selectedIcon: NavIcon +} + const AppDetailLayout: FC = (props) => { const { children, @@ -50,12 +57,7 @@ const AppDetailLayout: FC = (props) => { }))) const [isLoadingAppDetail, setIsLoadingAppDetail] = useState(false) const [appDetailRes, setAppDetailRes] = useState(null) - const [navigation, setNavigation] = useState>([]) + const [navigation, setNavigation] = useState>([]) const { systemFeatures } = useGlobalPublicStore() const getNavigations = useCallback((appId: string, isCurrentWorkspaceEditor: boolean, mode: string) => { @@ -142,15 +144,10 @@ const AppDetailLayout: FC = (props) => { router.replace(`/app/${appId}/configuration`) } else { - setAppDetail({ ...res, enable_sso: false }) - setNavigation(getNavigations(appId, isCurrentWorkspaceEditor, res.mode)) - if (systemFeatures.enable_web_sso_switch_component && canIEditApp) { - fetchAppSSO({ appId }).then((ssoRes) => { - setAppDetail({ ...res, enable_sso: ssoRes.enabled }) - }) - } + setAppDetail({ ...res }) + setNavigation(getNavigations(appId, isCurrentWorkspaceEditor, res.mode) as Array) } - }, [appDetailRes, appId, getNavigations, isCurrentWorkspaceEditor, isLoadingAppDetail, isLoadingCurrentWorkspace, pathname, router, setAppDetail, systemFeatures.enable_web_sso_switch_component]) + }, [appDetailRes, appId, getNavigations, isCurrentWorkspaceEditor, isLoadingAppDetail, isLoadingCurrentWorkspace, pathname, router, setAppDetail]) useUnmount(() => { setAppDetail() diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/cardView.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/cardView.tsx index 1285b2205c..02d858c01b 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/cardView.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/cardView.tsx @@ -8,19 +8,16 @@ import Loading from '@/app/components/base/loading' import { ToastContext } from '@/app/components/base/toast' import { fetchAppDetail, - fetchAppSSO, - updateAppSSO, updateAppSiteAccessToken, updateAppSiteConfig, updateAppSiteStatus, } from '@/service/apps' -import type { App, AppSSO } from '@/types/app' +import type { App } from '@/types/app' import type { UpdateAppSiteCodeResponse } from '@/models/app' import { asyncRunSafe } from '@/utils' import { NEED_REFRESH_APP_LIST_KEY } from '@/config' import type { IAppCardProps } from '@/app/components/app/overview/appCard' import { useStore as useAppStore } from '@/app/components/app/store' -import { useGlobalPublicStore } from '@/context/global-public-context' export type ICardViewProps = { appId: string @@ -31,18 +28,11 @@ const CardView: FC = ({ appId }) => { const { notify } = useContext(ToastContext) const appDetail = useAppStore(state => state.appDetail) const setAppDetail = useAppStore(state => state.setAppDetail) - const { systemFeatures } = useGlobalPublicStore() const updateAppDetail = async () => { try { const res = await fetchAppDetail({ url: '/apps', id: appId }) - if (systemFeatures.enable_web_sso_switch_component) { - const ssoRes = await fetchAppSSO({ appId }) - setAppDetail({ ...res, enable_sso: ssoRes.enabled }) - } - else { - setAppDetail({ ...res }) - } + setAppDetail({ ...res }) } catch (error) { console.error(error) } } @@ -93,16 +83,6 @@ const CardView: FC = ({ appId }) => { if (!err) localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1') - if (systemFeatures.enable_web_sso_switch_component) { - const [sso_err] = await asyncRunSafe( - updateAppSSO({ id: appId, enabled: Boolean(params.enable_sso) }) as Promise, - ) - if (sso_err) { - handleCallbackResult(sso_err) - return - } - } - handleCallbackResult(err) } diff --git a/web/app/(shareLayout)/webapp-signin/page.tsx b/web/app/(shareLayout)/webapp-signin/page.tsx index f3ca649468..d54bbe4dd3 100644 --- a/web/app/(shareLayout)/webapp-signin/page.tsx +++ b/web/app/(shareLayout)/webapp-signin/page.tsx @@ -1,7 +1,7 @@ 'use client' import { useRouter, useSearchParams } from 'next/navigation' import type { FC } from 'react' -import React, { useEffect } from 'react' +import React, { useCallback, useEffect } from 'react' import { useTranslation } from 'react-i18next' import cn from '@/utils/classnames' import Toast from '@/app/components/base/toast' @@ -9,6 +9,7 @@ import { fetchWebOAuth2SSOUrl, fetchWebOIDCSSOUrl, fetchWebSAMLSSOUrl } from '@/ import { setAccessToken } from '@/app/components/share/utils' import Button from '@/app/components/base/button' import { useGlobalPublicStore } from '@/context/global-public-context' +import { SSOProtocol } from '@/types/feature' const WebSSOForm: FC = () => { const { t } = useTranslation() @@ -27,15 +28,15 @@ const WebSSOForm: FC = () => { }) } - const getAppCodeFromRedirectUrl = () => { + const getAppCodeFromRedirectUrl = useCallback(() => { const appCode = redirectUrl?.split('/').pop() if (!appCode) return null return appCode - } + }, [redirectUrl]) - const processTokenAndRedirect = async () => { + const processTokenAndRedirect = useCallback(async () => { const appCode = getAppCodeFromRedirectUrl() if (!appCode || !tokenFromUrl || !redirectUrl) { showErrorToast('redirect url or app code or token is invalid.') @@ -44,7 +45,7 @@ const WebSSOForm: FC = () => { await setAccessToken(appCode, tokenFromUrl) router.push(redirectUrl) - } + }, [getAppCodeFromRedirectUrl, redirectUrl, router, tokenFromUrl]) const handleSSOLogin = async () => { const appCode = getAppCodeFromRedirectUrl() @@ -53,18 +54,18 @@ const WebSSOForm: FC = () => { return } - switch (systemFeatures.sso_enforced_for_web_protocol) { - case 'saml': { + switch (systemFeatures.webapp_auth.sso_config.protocol) { + case SSOProtocol.SAML: { const samlRes = await fetchWebSAMLSSOUrl(appCode, redirectUrl) router.push(samlRes.url) break } - case 'oidc': { + case SSOProtocol.OIDC: { const oidcRes = await fetchWebOIDCSSOUrl(appCode, redirectUrl) router.push(oidcRes.url) break } - case 'oauth2': { + case SSOProtocol.OAuth2: { const oauth2Res = await fetchWebOAuth2SSOUrl(appCode, redirectUrl) router.push(oauth2Res.url) break @@ -74,6 +75,14 @@ const WebSSOForm: FC = () => { } } + const goWebApp = () => { + if (!redirectUrl) { + showErrorToast('redirect url is invalid.') + return + } + router.push(redirectUrl) + } + useEffect(() => { const init = async () => { if (message) { @@ -88,15 +97,21 @@ const WebSSOForm: FC = () => { } init() - }, [message, tokenFromUrl]) // Added dependencies to useEffect - - return ( -
-
- + }, [message, processTokenAndRedirect, tokenFromUrl]) + if (systemFeatures.webapp_auth.enable) { + return ( +
+
+ +
+ ) + } + else { + return
+

Current App is not required for login, you can click here continue.

- ) + } } export default React.memo(WebSSOForm) diff --git a/web/app/components/app-sidebar/index.tsx b/web/app/components/app-sidebar/index.tsx index 61e4bf8330..7b0e8d9294 100644 --- a/web/app/components/app-sidebar/index.tsx +++ b/web/app/components/app-sidebar/index.tsx @@ -17,7 +17,7 @@ export type IAppDetailNavProps = { desc: string isExternal?: boolean icon: string - icon_background: string + icon_background: string | null navigation: Array<{ name: string href: string diff --git a/web/app/components/app/app-access-control/index.tsx b/web/app/components/app/app-access-control/index.tsx index 53f60f2481..23a5386965 100644 --- a/web/app/components/app/app-access-control/index.tsx +++ b/web/app/components/app/app-access-control/index.tsx @@ -30,7 +30,7 @@ export default function AccessControl(props: AccessControlProps) { const specificMembers = useAccessControlStore(s => s.specificMembers) const currentMenu = useAccessControlStore(s => s.currentMenu) const setCurrentMenu = useAccessControlStore(s => s.setCurrentMenu) - const hideTip = systemFeatures.enable_web_sso_switch_component && systemFeatures.sso_enforced_for_web + const hideTip = systemFeatures useEffect(() => { setAppId(app.id) diff --git a/web/app/components/app/app-access-control/specific-groups-or-members.tsx b/web/app/components/app/app-access-control/specific-groups-or-members.tsx index 414d8cce00..8d8e93b56a 100644 --- a/web/app/components/app/app-access-control/specific-groups-or-members.tsx +++ b/web/app/components/app/app-access-control/specific-groups-or-members.tsx @@ -20,7 +20,7 @@ export default function SpecificGroupsOrMembers() { const setSpecificMembers = useAccessControlStore(s => s.setSpecificMembers) const { t } = useTranslation() const systemFeatures = useGlobalPublicStore(s => s.systemFeatures) - const hideTip = systemFeatures.enable_web_sso_switch_component && systemFeatures.sso_enforced_for_web + const hideTip = systemFeatures.webapp_auth.enable const { isPending, data } = useAppWhiteListSubjects(appId, Boolean(appId) && currentMenu === AccessMode.SPECIFIC_GROUPS_MEMBERS) useEffect(() => { diff --git a/web/models/app.ts b/web/models/app.ts index edf8554457..e4383d4251 100644 --- a/web/models/app.ts +++ b/web/models/app.ts @@ -1,5 +1,5 @@ import type { LangFuseConfig, LangSmithConfig, OpikConfig, TracingProvider } from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type' -import type { App, AppSSO, AppTemplate, SiteConfig } from '@/types/app' +import type { App, AppTemplate, SiteConfig } from '@/types/app' /* export type App = { id: string @@ -89,8 +89,6 @@ export type DSLImportResponse = { error: string } -export type AppSSOResponse = { enabled: AppSSO['enable_sso'] } - export type AppTemplatesResponse = { data: AppTemplate[] } diff --git a/web/service/apps.ts b/web/service/apps.ts index 3f7ec7b548..d87a98412e 100644 --- a/web/service/apps.ts +++ b/web/service/apps.ts @@ -1,6 +1,6 @@ import type { Fetcher } from 'swr' import { del, get, patch, post, put } from './base' -import type { ApiKeysListResponse, AppDailyConversationsResponse, AppDailyEndUsersResponse, AppDailyMessagesResponse, AppDetailResponse, AppListResponse, AppSSOResponse, AppStatisticsResponse, AppTemplatesResponse, AppTokenCostsResponse, AppVoicesListResponse, CreateApiKeyResponse, DSLImportMode, DSLImportResponse, GenerationIntroductionResponse, TracingConfig, TracingStatus, UpdateAppModelConfigResponse, UpdateAppSiteCodeResponse, UpdateOpenAIKeyResponse, ValidateOpenAIKeyResponse, WorkflowDailyConversationsResponse } from '@/models/app' +import type { ApiKeysListResponse, AppDailyConversationsResponse, AppDailyEndUsersResponse, AppDailyMessagesResponse, AppDetailResponse, AppListResponse, AppStatisticsResponse, AppTemplatesResponse, AppTokenCostsResponse, AppVoicesListResponse, CreateApiKeyResponse, DSLImportMode, DSLImportResponse, GenerationIntroductionResponse, TracingConfig, TracingStatus, UpdateAppModelConfigResponse, UpdateAppSiteCodeResponse, UpdateOpenAIKeyResponse, ValidateOpenAIKeyResponse, WorkflowDailyConversationsResponse } from '@/models/app' import type { CommonResponse } from '@/models/common' import type { AppIconType, AppMode, ModelConfig } from '@/types/app' import type { TracingProvider } from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type' @@ -13,13 +13,6 @@ export const fetchAppDetail = ({ url, id }: { url: string; id: string }) => { return get(`${url}/${id}`) } -export const fetchAppSSO = async ({ appId }: { appId: string }) => { - return get(`/enterprise/app-setting/sso?appID=${appId}`) -} -export const updateAppSSO = async ({ id, enabled }: { id: string; enabled: boolean }) => { - return post('/enterprise/app-setting/sso', { body: { app_id: id, enabled } }) -} - export const fetchAppTemplates: Fetcher = ({ url }) => { return get(url) } diff --git a/web/service/base.ts b/web/service/base.ts index 22b1a43ad1..5798af1bbf 100644 --- a/web/service/base.ts +++ b/web/service/base.ts @@ -512,7 +512,7 @@ export const ssePost = ( }).catch(() => { res.json().then((data: any) => { if (isPublicAPI) { - if (data.code === 'web_sso_auth_required') + if (data.code === 'web_sso_auth_required' || data.code === 'web_app_access_denied') requiredWebSSOLogin() if (data.code === 'unauthorized') { @@ -566,7 +566,7 @@ export const request = async(url: string, options = {}, otherOptions?: IOther // special code const { code, message } = errRespData // webapp sso - if (code === 'web_sso_auth_required') { + if (code === 'web_sso_auth_required' || code === 'web_app_access_denied') { requiredWebSSOLogin() return Promise.reject(err) } diff --git a/web/types/feature.ts b/web/types/feature.ts index df7a134a04..bdbd0a4d4b 100644 --- a/web/types/feature.ts +++ b/web/types/feature.ts @@ -21,9 +21,6 @@ type License = { export type SystemFeatures = { sso_enforced_for_signin: boolean sso_enforced_for_signin_protocol: SSOProtocol | '' - sso_enforced_for_web: boolean - sso_enforced_for_web_protocol: SSOProtocol | '' - enable_web_sso_switch_component: boolean enable_email_code_login: boolean enable_email_password_login: boolean enable_social_oauth_login: boolean @@ -38,14 +35,18 @@ export type SystemFeatures = { favicon: string application_title: string } + webapp_auth: { + enable: boolean + allow_sso: boolean + sso_config: { + protocol: SSOProtocol + } + } } export const defaultSystemFeatures: SystemFeatures = { sso_enforced_for_signin: false, sso_enforced_for_signin_protocol: '', - sso_enforced_for_web: false, - sso_enforced_for_web_protocol: '', - enable_web_sso_switch_component: false, enable_email_code_login: false, enable_email_password_login: false, enable_social_oauth_login: false, @@ -63,4 +64,11 @@ export const defaultSystemFeatures: SystemFeatures = { favicon: '', application_title: 'test title', }, + webapp_auth: { + enable: false, + allow_sso: false, + sso_config: { + protocol: SSOProtocol.SAML, + }, + }, }