mirror of
https://github.com/langgenius/dify.git
synced 2026-05-10 05:56:31 +08:00
feat(logout): implement logout mutation and reset login cache on success
test(logout): add unit tests for useLogout hook to verify cache reset refactor(signin): enhance signin URL handling for OAuth and generic redirects
This commit is contained in:
parent
acbcca0322
commit
3a8bbd10cd
@ -23,6 +23,23 @@ describe('buildSigninUrlWithRedirect', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('Non-OAuth redirect handling', () => {
|
||||
it('should return plain signin URL without oauth_redirect_url for generic pages', () => {
|
||||
// Arrange
|
||||
const currentLocation = {
|
||||
origin: 'https://example.com',
|
||||
pathname: '/apps',
|
||||
search: '?tab=all',
|
||||
} as const
|
||||
|
||||
// Act
|
||||
const signinUrl = buildSigninUrlWithRedirect(currentLocation, '')
|
||||
|
||||
// Assert
|
||||
expect(signinUrl).toBe('https://example.com/signin')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Signin self-redirect guard', () => {
|
||||
it('should return plain signin URL when current path is already signin', () => {
|
||||
// Arrange
|
||||
@ -41,12 +58,12 @@ describe('buildSigninUrlWithRedirect', () => {
|
||||
})
|
||||
|
||||
describe('basePath support', () => {
|
||||
it('should respect basePath when building signin URL', () => {
|
||||
it('should respect basePath for OAuth authorize path', () => {
|
||||
// Arrange
|
||||
const currentLocation = {
|
||||
origin: 'https://example.com',
|
||||
pathname: '/console/apps',
|
||||
search: '?tab=all',
|
||||
pathname: '/console/account/oauth/authorize',
|
||||
search: '?client_id=abc',
|
||||
} as const
|
||||
|
||||
// Act
|
||||
@ -55,7 +72,7 @@ describe('buildSigninUrlWithRedirect', () => {
|
||||
// Assert
|
||||
expect(signinUrl.startsWith('https://example.com/console/signin?')).toBe(true)
|
||||
const encodedRedirect = new URL(signinUrl).searchParams.get('oauth_redirect_url')
|
||||
expect(decodeURIComponent(encodedRedirect || '')).toBe('https://example.com/console/apps?tab=all')
|
||||
expect(decodeURIComponent(encodedRedirect || '')).toBe('https://example.com/console/account/oauth/authorize?client_id=abc')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -38,6 +38,7 @@ import { getWebAppPassport } from './webapp-auth'
|
||||
|
||||
const TIME_OUT = 100000
|
||||
const SIGNIN_REDIRECT_URL_KEY = 'oauth_redirect_url'
|
||||
const OAUTH_AUTHORIZE_PATH = '/account/oauth/authorize'
|
||||
|
||||
export type IconObject = {
|
||||
background: string
|
||||
@ -160,11 +161,17 @@ function jumpTo(url: string) {
|
||||
export function buildSigninUrlWithRedirect(currentLocation: Pick<Location, 'origin' | 'pathname' | 'search'>, currentBasePath: string) {
|
||||
const signinPath = `${currentBasePath}/signin`
|
||||
const signinUrl = `${currentLocation.origin}${signinPath}`
|
||||
const oauthAuthorizePath = `${currentBasePath}${OAUTH_AUTHORIZE_PATH}`
|
||||
|
||||
// Keep signin as-is to avoid redirect loops.
|
||||
if (currentLocation.pathname === signinPath)
|
||||
return signinUrl
|
||||
|
||||
// Only OAuth authorization flow requires preserving the full original URL.
|
||||
// For generic 401 redirects (e.g. manual logout), keep signin URL clean.
|
||||
if (currentLocation.pathname !== oauthAuthorizePath)
|
||||
return signinUrl
|
||||
|
||||
const currentUrl = `${currentLocation.origin}${currentLocation.pathname}${currentLocation.search}`
|
||||
const params = new URLSearchParams()
|
||||
params.set(SIGNIN_REDIRECT_URL_KEY, encodeURIComponent(currentUrl))
|
||||
|
||||
43
web/service/use-common.spec.tsx
Normal file
43
web/service/use-common.spec.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||
import { act, renderHook } from '@testing-library/react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { post } from './base'
|
||||
import { commonQueryKeys, useLogout } from './use-common'
|
||||
|
||||
vi.mock('./base', () => ({
|
||||
get: vi.fn(),
|
||||
post: vi.fn(),
|
||||
}))
|
||||
|
||||
const createWrapper = (queryClient: QueryClient) => {
|
||||
return ({ children }: { children: ReactNode }) => (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
{children}
|
||||
</QueryClientProvider>
|
||||
)
|
||||
}
|
||||
|
||||
describe('useLogout', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('should reset login cache when logout succeeds', async () => {
|
||||
// Arrange
|
||||
const queryClient = new QueryClient()
|
||||
const wrapper = createWrapper(queryClient)
|
||||
queryClient.setQueryData(commonQueryKeys.isLogin, { logged_in: true })
|
||||
vi.mocked(post).mockResolvedValue({ result: 'success' } as never)
|
||||
const { result } = renderHook(() => useLogout(), { wrapper })
|
||||
|
||||
// Act
|
||||
await act(async () => {
|
||||
await result.current.mutateAsync()
|
||||
})
|
||||
|
||||
// Assert
|
||||
expect(post).toHaveBeenCalledWith('/logout')
|
||||
expect(queryClient.getQueryData(commonQueryKeys.isLogin)).toEqual({ logged_in: false })
|
||||
})
|
||||
})
|
||||
@ -22,7 +22,7 @@ import type {
|
||||
UserProfileResponse,
|
||||
} from '@/models/common'
|
||||
import type { RETRIEVE_METHOD } from '@/types/app'
|
||||
import { useMutation, useQuery } from '@tanstack/react-query'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { IS_DEV } from '@/config'
|
||||
import { get, post } from './base'
|
||||
import { useInvalid } from './use-base'
|
||||
@ -232,9 +232,15 @@ export const useIsLogin = () => {
|
||||
}
|
||||
|
||||
export const useLogout = () => {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
mutationKey: [NAME_SPACE, 'logout'],
|
||||
mutationFn: () => post('/logout'),
|
||||
onSuccess: () => {
|
||||
queryClient.setQueryData(commonQueryKeys.isLogin, { logged_in: false })
|
||||
queryClient.removeQueries({ queryKey: commonQueryKeys.userProfile })
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user