feat(web): sso

This commit is contained in:
zhaoying
2026-02-04 17:47:46 +08:00
parent 161da723b9
commit 7e0b31626f
5 changed files with 63 additions and 8 deletions

View File

@@ -37,7 +37,7 @@ function App() {
const { checkJump } = useUser();
useEffect(() => {
const authToken = cookieUtils.get('authToken')
if (!authToken && !window.location.hash.includes('#/login') && !window.location.hash.includes('#/conversation/')) {
if (!authToken && !window.location.hash.includes('#/login') && !window.location.hash.includes('#/conversation/') && !window.location.hash.includes('#/jump')) {
window.location.href = `/#/login`;
} else {
checkJump()

View File

@@ -1,8 +1,8 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-02 16:33:11
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-02 16:33:11
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-04 18:11:34
*/
/**
* Route Configuration
@@ -23,7 +23,6 @@ import { createHashRouter, createRoutesFromElements, Route } from 'react-router-
/** Import route configuration JSON */
import routesConfig from './routes.json';
/** Recursively collect all element names from routes */
function collectElements(routes: RouteConfig[]): Set<string> {
const elements = new Set<string>();
@@ -88,6 +87,7 @@ const componentMap: Record<string, LazyExoticComponent<ComponentType<object>>> =
Ontology: lazy(() => import('@/views/Ontology')),
OntologyDetail: lazy(() => import('@/views/Ontology/pages/Detail')),
Prompt: lazy(() => import('@/views/Prompt')),
Jump: lazy(() => import('@/views/JumpPage')),
Login: lazy(() => import('@/views/Login')),
InviteRegister: lazy(() => import('@/views/InviteRegister')),
NoPermission: lazy(() => import('@/views/NoPermission')),

View File

@@ -53,7 +53,8 @@
{
"element": "NoAuthLayout",
"children": [
{ "path": "/conversation/:token", "element": "Conversation" }
{ "path": "/conversation/:token", "element": "Conversation" },
{ "path": "/jump", "element": "Jump" }
]
},
{

View File

@@ -1,8 +1,8 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-02 16:33:54
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-02 16:33:54
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-04 18:30:10
*/
/**
* User Store
@@ -59,7 +59,8 @@ export interface UserState {
export const whitePage = [
'/conversation',
'/login',
'/invite-register'
'/invite-register',
'jump'
]
/** User store */

View File

@@ -0,0 +1,53 @@
/*
* @Author: ZhaoYing
* @Date: 2026-02-04 18:34:36
* @Last Modified by: ZhaoYing
* @Last Modified time: 2026-02-04 18:34:36
*/
import { useEffect, type FC } from 'react'
import { useNavigate, useSearchParams } from 'react-router-dom'
import { cookieUtils } from '@/utils/request'
/**
* JumpPage Component
*
* This is an intermediate redirect page used for OAuth authentication flow.
* It handles the callback from external authentication providers by:
* 1. Extracting authentication tokens from URL query parameters
* 2. Storing tokens in cookies for subsequent API requests
* 3. Redirecting users to their intended destination
*
* Expected URL format:
* /jump?access_token=xxx&refresh_token=yyy&target=/dashboard
*
* @returns null - This component doesn't render any UI, it only handles side effects
*/
const JumpPage: FC = () => {
const navigate = useNavigate()
const [searchParams] = useSearchParams()
useEffect(() => {
// Convert URLSearchParams to a plain object for easier access
const data = Object.fromEntries(searchParams)
const { access_token, refresh_token, target } = data
// Store authentication tokens in cookies for API authorization
cookieUtils.set('access_token', access_token)
cookieUtils.set('refresh_token', refresh_token)
// Redirect to the target page if specified
if (target) {
// Use setTimeout to ensure cookie operations complete before navigation
setTimeout(() => {
// Replace current history entry to prevent users from going back to this page
navigate(target, { replace: true })
}, 0)
}
}, [searchParams, navigate])
// No UI rendering needed - this is a pure redirect handler
return null
}
export default JumpPage