mirror of
https://github.com/MoonTechLab/LunaTV.git
synced 2026-05-13 07:57:29 +08:00
feat(AuthProvider): 添加认证状态管理和加载界面
重构认证逻辑为独立函数并添加状态管理,在认证过程中显示加载界面。同时添加主题切换按钮到加载界面。
This commit is contained in:
@@ -1,7 +1,11 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { usePathname, useRouter } from 'next/navigation';
|
import { usePathname, useRouter } from 'next/navigation';
|
||||||
import { useEffect } from 'react';
|
import { useCallback, useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import { ThemeToggle } from '@/components/ThemeToggle';
|
||||||
|
|
||||||
|
import { useSite } from './SiteProvider';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
@@ -10,37 +14,73 @@ interface Props {
|
|||||||
export default function AuthProvider({ children }: Props) {
|
export default function AuthProvider({ children }: Props) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
|
const [isAuthenticated, setIsAuthenticated] = useState<boolean | null>(null);
|
||||||
|
const { siteName } = useSite();
|
||||||
|
const authenticate = useCallback(async () => {
|
||||||
|
// 登录页
|
||||||
|
if (pathname.startsWith('/login') || pathname.startsWith('/api/login')) {
|
||||||
|
setIsAuthenticated(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
// 从localStorage获取密码
|
||||||
// 登录页或 API 路径不做校验,避免死循环
|
|
||||||
if (pathname.startsWith('/login')) return;
|
|
||||||
|
|
||||||
const password = localStorage.getItem('password');
|
const password = localStorage.getItem('password');
|
||||||
const fullPath =
|
const fullPath =
|
||||||
typeof window !== 'undefined'
|
typeof window !== 'undefined'
|
||||||
? window.location.pathname + window.location.search
|
? window.location.pathname + window.location.search
|
||||||
: pathname;
|
: pathname;
|
||||||
|
|
||||||
// 有密码时验证
|
// 没有密码直接跳转
|
||||||
(async () => {
|
if (!password) {
|
||||||
try {
|
router.replace(`/login?redirect=${encodeURIComponent(fullPath)}`);
|
||||||
const res = await fetch('/api/login', {
|
setIsAuthenticated(false);
|
||||||
method: 'POST',
|
return;
|
||||||
headers: { 'Content-Type': 'application/json' },
|
}
|
||||||
body: JSON.stringify({ password }),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!res.ok) {
|
// 尝试认证
|
||||||
// 校验未通过,清理并跳转登录
|
try {
|
||||||
localStorage.removeItem('password');
|
const res = await fetch('/api/login', {
|
||||||
router.replace(`/login?redirect=${encodeURIComponent(fullPath)}`);
|
method: 'POST',
|
||||||
}
|
headers: { 'Content-Type': 'application/json' },
|
||||||
} catch (error) {
|
body: JSON.stringify({ password }),
|
||||||
// 网络错误等也认为未登录
|
});
|
||||||
router.replace(`/login?redirect=${encodeURIComponent(fullPath)}`);
|
|
||||||
}
|
if (!res.ok) throw new Error('认证失败');
|
||||||
})();
|
|
||||||
|
setIsAuthenticated(true);
|
||||||
|
} catch (error) {
|
||||||
|
// 认证失败,清理并跳转登录
|
||||||
|
setIsAuthenticated(false);
|
||||||
|
localStorage.removeItem('password');
|
||||||
|
router.replace(`/login?redirect=${encodeURIComponent(fullPath)}`);
|
||||||
|
}
|
||||||
}, [pathname, router]);
|
}, [pathname, router]);
|
||||||
|
|
||||||
return <>{children}</>;
|
useEffect(() => {
|
||||||
|
authenticate();
|
||||||
|
}, [pathname, authenticate]);
|
||||||
|
|
||||||
|
// 认证状态未知时显示加载状态
|
||||||
|
if (!isAuthenticated) {
|
||||||
|
return (
|
||||||
|
<div className='relative min-h-screen flex items-center justify-center px-4 overflow-hidden'>
|
||||||
|
<div className='absolute top-4 right-4'>
|
||||||
|
<ThemeToggle />
|
||||||
|
</div>
|
||||||
|
<div className='relative z-10 w-full max-w-md rounded-3xl bg-gradient-to-b from-white/90 via-white/70 to-white/40 dark:from-zinc-900/90 dark:via-zinc-900/70 dark:to-zinc-900/40 backdrop-blur-xl shadow-2xl p-10 dark:border dark:border-zinc-800'>
|
||||||
|
<h1 className='text-green-600 tracking-tight text-center text-3xl font-extrabold mb-8 bg-clip-text drop-shadow-sm'>
|
||||||
|
{siteName}
|
||||||
|
</h1>
|
||||||
|
<div className='flex justify-center my-10'>
|
||||||
|
<div className='animate-spin rounded-full h-16 w-16 border-t-4 border-b-4 border-green-500' />
|
||||||
|
</div>
|
||||||
|
<p className='text-gray-700 dark:text-gray-300 font-medium text-lg text-center'>
|
||||||
|
正在验证您的身份,请稍候...
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return <>{children}</>;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user