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

Next.js页面角色权限自动化配置及预加载校验问题解决

Next.js 页面权限前置校验方案

需求

路由信息变更时,需先完成用户角色获取与校验,再决定是否进入目标页面:

  • 权限匹配:加载页面并允许访问
  • 无权限:直接重定向至错误页面,不加载目标页面
    需实现一套算法,管控user_app下所有页面的访问权限。

现有流程

  • 用户访问页面时,获取当前路径信息
  • 通过路径从process.env中读取该页面的权限配置
  • 从Cookie/Token中提取用户角色信息
  • 对比用户角色与页面权限,有权限则允许访问,无权限则重定向至404页面

当前问题

当前控制逻辑在用户进入页面后触发,校验函数执行期间目标页面会短暂可访问,需实现页面加载前的权限校验,通过后再加载页面数据。

解决方案(基于Next.js路由拦截)

在Next.js中,要彻底解决页面闪烁问题,需利用服务端或路由拦截能力在页面渲染前完成校验。以下针对Page Router场景给出改造方案:

核心思路

  1. 封装独立的权限校验工具函数,统一处理角色校验逻辑
  2. 利用getServerSideProps(SSR场景)实现服务端前置校验,直接在服务端完成重定向
  3. 可选配置客户端路由监听,作为服务端校验的补充

代码实现

1. 封装权限校验工具函数

// utils/roleCheck.js
import axios from 'axios';
import decrypted from '../crypto/decrypted';

export async function checkUserRole(path) {
  // 获取当前页面的权限配置
  const pageRoles = process.env.pageLinks[path];
  // 无权限配置默认拒绝访问
  if (!pageRoles) {
    return { hasPermission: false };
  }

  try {
    const res = await axios.get(`${process.env.NEXT_PUBLIC_API_URL}/token/GET`);
    // 存在有效用户信息时校验角色
    if (res.data.success && res.data.Acoount != null) {
      const decryptedValue = decrypted(res.data.Acoount);
      const userRole = decryptedValue.role;
      
      // 权限匹配逻辑:用户角色在允许列表中,且不是公开页面(0代表公开)或路径为根目录
      const hasPermission = pageRoles.includes(userRole) && (!pageRoles.includes(0) || path === "/");
      return { hasPermission };
    } else {
      // 无用户信息时,检查是否为公开页面
      return { hasPermission: pageRoles.includes(0) };
    }
  } catch (error) {
    console.error('权限校验失败:', error);
    return { hasPermission: false };
  }
}

2. 页面级前置校验(服务端)

在user_app下的所有页面组件中添加getServerSideProps,实现页面渲染前的服务端校验:

// pages/user_app/target-page.js(示例页面)
import React from 'react';
import { checkUserRole } from '../../utils/roleCheck';

const TargetPage = () => {
  return <div>有权限访问的页面内容</div>;
};

export async function getServerSideProps(context) {
  const { res } = context;
  const path = context.resolvedUrl;

  const { hasPermission } = await checkUserRole(path);
  
  if (!hasPermission) {
    // 服务端直接重定向到404,避免客户端页面加载
    res.writeHead(302, { Location: '/404' });
    res.end();
    return { props: {} };
  }

  return {
    props: {}, // 传递给页面组件的参数
  };
}

export default TargetPage;

3. 全局路由拦截(客户端补充)

如果需要统一管控所有页面,可在_app.js中监听路由变更事件,作为服务端校验的补充:

// pages/_app.js
import { useEffect } from 'react';
import { useRouter } from 'next/router';
import { checkUserRole } from '../utils/roleCheck';

function MyApp({ Component, pageProps }) {
  const router = useRouter();

  useEffect(() => {
    const handleRouteChange = async (url) => {
      // 避免重复校验404页面
      if (url === '/404') return;
      
      const { hasPermission } = await checkUserRole(url);
      if (!hasPermission) {
        router.replace('/404');
      }
    };

    // 监听路由开始变更事件
    router.events.on('routeChangeStart', handleRouteChange);

    return () => {
      // 组件卸载时移除监听
      router.events.off('routeChangeStart', handleRouteChange);
    };
  }, [router]);

  return <Component {...pageProps} />;
}

export default MyApp;

关键说明

  • 服务端校验优先:getServerSideProps能在页面渲染前完成校验,彻底避免页面闪烁问题
  • 权限配置准确性:确保process.env.pageLinks中的路径与实际页面路径完全匹配
  • 异常处理:网络请求失败时默认拒绝访问,防止未授权用户绕过校验

内容的提问来源于stack exchange,提问作者Enes Gülcü

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 15:55:36