You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS如何实现未认证用户无页面闪烁重定向?

解决未认证用户访问管理员控制台的页面闪烁问题

我已经完成页面的管理员权限认证配置,权限路由保护功能正常(采用基于Token的认证而非Cookie认证),但目前存在一个问题:未认证用户访问管理员控制台时,页面会先短暂显示内容再重定向,希望避免这种闪烁现象。

当前使用的代码

import { useRouter } from "next/router"
import { useState, useEffect } from "react";
import useSWR from 'swr';
import axios from "../lib/axios";


export const useAuth = ({ middleware } = {}) => {
    const router = useRouter();

    // LOADING
    const [isLoading, setisLoading] = useState(true);

    // USER
    const { data: user, error, mutate } = useSWR('/api/user', () =>
        axios
            .get('/api/user')
            .then(res => res.data)
            .catch(error => {
                if (error.response.status !== 401) throw error

                router.push('/')
            }),
    )

    // CSRF
    const csrf = () => axios.get('/sanctum/csrf-cookie'); // 我用的是Token认证,不知道怎么修改这个

    // LOGOUT
    const logout = async () => {
        await axios.post('/api/logout');
        mutate(null);
        router.push("/login");
    }

    useEffect(() => {
        if (user || error) {
            setisLoading(false);
        }

        if (middleware == "guest" && user) router.push("/");
        if (middleware == "auth" && error) router.push("/login");


    })

    return {
        user,
        csrf,
        logout,
        isLoading
    }
}

尝试过的无效代码

useEffect(() => {
    axios.get(`/api/user`).then(res => {
        if (res.status === 200) {
            console.log('nice');
        }
        setLoading(false);
    });
}, []);

axios.interceptors.response.use(undefined, function axiosRetryInterceptor(err) {
    if (err.response.status === 401) {
        router.push('/');
    }
    return Promise.reject(err);
});

可行解决方案

页面闪烁的核心原因是:认证状态未确认前就渲染了管理员页面内容,后续才触发重定向。解决思路是在认证状态明确前,不渲染页面核心内容,仅展示加载状态,同时优化认证逻辑的执行时机。

1. 修复useAuth钩子的核心问题

import { useRouter } from "next/router"
import { useState, useEffect } from "react";
import useSWR from 'swr';
import axios from "../lib/axios";

export const useAuth = ({ middleware } = {}) => {
    const router = useRouter();
    const [isLoading, setIsLoading] = useState(true);

    // 用SWR获取用户信息,仅抛出错误由SWR统一管理状态
    const { data: user, error, mutate } = useSWR('/api/user', async () => {
        try {
            const res = await axios.get('/api/user');
            return res.data;
        } catch (err) {
            // 直接抛出错误,让SWR捕获error状态
            throw err;
        }
    });

    // 移除无用的CSRF方法(Token认证无需Sanctum CSRF Cookie)
    // LOGOUT
    const logout = async () => {
        await axios.post('/api/logout');
        mutate(null);
        router.push("/login");
    }

    // 给useEffect添加依赖项,避免无限触发;仅在状态明确后关闭加载态
    useEffect(() => {
        if (user || error) {
            setIsLoading(false);
        }

        // 根据中间件类型处理路由跳转
        if (middleware === "guest" && user) {
            router.push("/");
        }
        if (middleware === "auth" && error) {
            // 仅在401未认证时跳转登录页
            if (error.response?.status === 401) {
                router.push("/login");
            }
        }
    }, [user, error, middleware, router]); // 必须添加依赖项

    return {
        user,
        logout,
        isLoading
    }
}

2. 配置Axios自动携带Token(关键)

在你的../lib/axios文件中添加请求拦截器,确保每次请求自动带上认证Token(假设Token存在localStorage中):

import axios from 'axios';

const axiosInstance = axios.create({
    baseURL: process.env.NEXT_PUBLIC_API_URL // 替换为你的API地址
});

// 请求拦截器:自动在请求头添加Token
axiosInstance.interceptors.request.use((config) => {
    const token = localStorage.getItem('auth_token');
    if (token) {
        config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
});

export default axiosInstance;

3. 管理员页面组件中控制渲染逻辑

在管理员控制台页面,先判断isLoading状态,加载完成前仅展示加载占位(如空白、骨架屏),不渲染核心内容:

import { useAuth } from '../hooks/useAuth';

export default function AdminDashboard() {
    const { user, isLoading } = useAuth({ middleware: 'auth' });

    // 加载状态下仅展示加载提示,不渲染管理员内容
    if (isLoading) {
        return <div>加载中...</div>; // 可替换为骨架屏组件
    }

    // 加载完成后渲染管理员页面内容
    return (
        <div>
            <h1>管理员控制台</h1>
            {/* 其他页面内容 */}
        </div>
    );
}

关键说明

  • 移除了无用的CSRF方法:Token认证模式下不需要Sanctum的CSRF Cookie请求,直接删除即可。
  • 修复useEffect依赖:之前的useEffect没有依赖项会导致无限触发,添加依赖后仅在状态变化时执行逻辑。
  • 延迟页面渲染:通过isLoading状态控制,确保认证结果返回前不渲染敏感内容,从根源避免闪烁。

内容的提问来源于stack exchange,提问作者Babaduk98

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 09:15:38