mirror of
https://github.com/iflytek/skillhub.git
synced 2026-10-07 02:57:51 +00:00
fix(web): redirect unauthenticated users back after login
This commit is contained in:
parent
f16885a39d
commit
c499571408
5 changed files with 52 additions and 16 deletions
|
|
@ -71,6 +71,7 @@ export function Layout() {
|
|||
) : (
|
||||
<Link
|
||||
to="/login"
|
||||
search={{ returnTo: '' }}
|
||||
className="text-sm font-medium text-muted-foreground hover:text-foreground transition-colors"
|
||||
activeProps={{ className: 'text-primary' }}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -42,10 +42,17 @@ const rootRoute = createRootRoute({
|
|||
component: Layout,
|
||||
})
|
||||
|
||||
async function requireAuth() {
|
||||
function buildReturnTo(location: { pathname: string; searchStr?: string; hash?: string }) {
|
||||
return `${location.pathname}${location.searchStr ?? ''}${location.hash ?? ''}`
|
||||
}
|
||||
|
||||
async function requireAuth({ location }: { location: { pathname: string; searchStr?: string; hash?: string } }) {
|
||||
const user = await getCurrentUser()
|
||||
if (!user) {
|
||||
throw redirect({ to: '/login' })
|
||||
throw redirect({
|
||||
to: '/login',
|
||||
search: { returnTo: buildReturnTo(location) },
|
||||
})
|
||||
}
|
||||
return { user }
|
||||
}
|
||||
|
|
@ -59,12 +66,18 @@ const skillsRoute = createRoute({
|
|||
const loginRoute = createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
path: 'login',
|
||||
validateSearch: (search: Record<string, unknown>) => ({
|
||||
returnTo: typeof search.returnTo === 'string' ? search.returnTo : '',
|
||||
}),
|
||||
component: LoginPage,
|
||||
})
|
||||
|
||||
const registerRoute = createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
path: 'register',
|
||||
validateSearch: (search: Record<string, unknown>) => ({
|
||||
returnTo: typeof search.returnTo === 'string' ? search.returnTo : '',
|
||||
}),
|
||||
component: RegisterPage,
|
||||
})
|
||||
|
||||
|
|
@ -152,8 +165,8 @@ const dashboardReviewDetailRoute = createRoute({
|
|||
const dashboardPromotionsRoute = createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
path: 'dashboard/promotions',
|
||||
beforeLoad: async () => {
|
||||
const { user } = await requireAuth()
|
||||
beforeLoad: async (ctx) => {
|
||||
const { user } = await requireAuth(ctx)
|
||||
if (!user.platformRoles?.includes('SKILL_ADMIN') && !user.platformRoles?.includes('SUPER_ADMIN')) {
|
||||
throw redirect({ to: '/dashboard' })
|
||||
}
|
||||
|
|
@ -199,8 +212,8 @@ const settingsAccountsRoute = createRoute({
|
|||
const adminUsersRoute = createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
path: 'admin/users',
|
||||
beforeLoad: async () => {
|
||||
const { user } = await requireAuth()
|
||||
beforeLoad: async (ctx) => {
|
||||
const { user } = await requireAuth(ctx)
|
||||
if (!user.platformRoles?.includes('USER_ADMIN') && !user.platformRoles?.includes('SUPER_ADMIN')) {
|
||||
throw redirect({ to: '/dashboard' })
|
||||
}
|
||||
|
|
@ -212,8 +225,8 @@ const adminUsersRoute = createRoute({
|
|||
const adminAuditLogRoute = createRoute({
|
||||
getParentRoute: () => rootRoute,
|
||||
path: 'admin/audit-log',
|
||||
beforeLoad: async () => {
|
||||
const { user } = await requireAuth()
|
||||
beforeLoad: async (ctx) => {
|
||||
const { user } = await requireAuth(ctx)
|
||||
if (!user.platformRoles?.includes('AUDITOR') && !user.platformRoles?.includes('SUPER_ADMIN')) {
|
||||
throw redirect({ to: '/dashboard' })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Link } from '@tanstack/react-router'
|
||||
import { Link, useNavigate, useSearch } from '@tanstack/react-router'
|
||||
import { useState } from 'react'
|
||||
import { LoginButton } from '@/features/auth/login-button'
|
||||
import { useLocalLogin } from '@/features/auth/use-local-auth'
|
||||
|
|
@ -7,15 +7,19 @@ import { Input } from '@/shared/ui/input'
|
|||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/shared/ui/tabs'
|
||||
|
||||
export function LoginPage() {
|
||||
const navigate = useNavigate()
|
||||
const search = useSearch({ from: '/login' })
|
||||
const loginMutation = useLocalLogin()
|
||||
const [username, setUsername] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
|
||||
const returnTo = search.returnTo && search.returnTo.startsWith('/') ? search.returnTo : '/dashboard'
|
||||
|
||||
async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault()
|
||||
try {
|
||||
await loginMutation.mutateAsync({ username, password })
|
||||
window.location.href = '/dashboard'
|
||||
await navigate({ to: returnTo })
|
||||
} catch {
|
||||
// mutation state drives the error UI
|
||||
}
|
||||
|
|
@ -73,7 +77,11 @@ export function LoginPage() {
|
|||
<p className="text-center text-sm text-muted-foreground">
|
||||
还没有账号?
|
||||
{' '}
|
||||
<Link to="/register" className="font-medium text-primary hover:underline">
|
||||
<Link
|
||||
to="/register"
|
||||
search={{ returnTo }}
|
||||
className="font-medium text-primary hover:underline"
|
||||
>
|
||||
立即注册
|
||||
</Link>
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Link } from '@tanstack/react-router'
|
||||
import { Link, useNavigate, useSearch } from '@tanstack/react-router'
|
||||
import { useState } from 'react'
|
||||
import { LoginButton } from '@/features/auth/login-button'
|
||||
import { useLocalRegister } from '@/features/auth/use-local-auth'
|
||||
|
|
@ -8,16 +8,20 @@ import { Input } from '@/shared/ui/input'
|
|||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/shared/ui/tabs'
|
||||
|
||||
export function RegisterPage() {
|
||||
const navigate = useNavigate()
|
||||
const search = useSearch({ from: '/register' })
|
||||
const registerMutation = useLocalRegister()
|
||||
const [username, setUsername] = useState('')
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
|
||||
const returnTo = search.returnTo && search.returnTo.startsWith('/') ? search.returnTo : '/dashboard'
|
||||
|
||||
async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault()
|
||||
try {
|
||||
await registerMutation.mutateAsync({ username, email, password })
|
||||
window.location.href = '/dashboard'
|
||||
await navigate({ to: returnTo })
|
||||
} catch {
|
||||
// mutation state drives the error UI
|
||||
}
|
||||
|
|
@ -80,7 +84,11 @@ export function RegisterPage() {
|
|||
<p className="text-center text-sm text-muted-foreground">
|
||||
已有账号?
|
||||
{' '}
|
||||
<Link to="/login" className="font-medium text-primary hover:underline">
|
||||
<Link
|
||||
to="/login"
|
||||
search={{ returnTo }}
|
||||
className="font-medium text-primary hover:underline"
|
||||
>
|
||||
返回登录
|
||||
</Link>
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { useParams, useNavigate } from '@tanstack/react-router'
|
||||
import { useParams, useNavigate, useRouterState } from '@tanstack/react-router'
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { MarkdownRenderer } from '@/features/skill/markdown-renderer'
|
||||
import { FileTree } from '@/features/skill/file-tree'
|
||||
|
|
@ -20,6 +20,7 @@ import {
|
|||
|
||||
export function SkillDetailPage() {
|
||||
const navigate = useNavigate()
|
||||
const location = useRouterState({ select: (s) => s.location })
|
||||
const queryClient = useQueryClient()
|
||||
const { namespace, slug } = useParams({ from: '/@$namespace/$slug' })
|
||||
const { user, hasRole } = useAuth()
|
||||
|
|
@ -53,7 +54,12 @@ export function SkillDetailPage() {
|
|||
})
|
||||
|
||||
const requireLogin = () => {
|
||||
navigate({ to: '/login' })
|
||||
navigate({
|
||||
to: '/login',
|
||||
search: {
|
||||
returnTo: `${location.pathname}${location.searchStr}${location.hash}`,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if (isLoadingSkill) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue