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

Next.js URL重写需求:隐藏角色实现/admin/dashboard映射到/dashboard

解决方案:隐藏URL角色标识并兼容客户端/服务端路由

1. 统一页面入口:创建共享的/dashboard页面

在pages目录下新建dashboard.js(或dashboard/index.js),作为所有角色访问/dashboard的统一入口,根据用户角色动态渲染对应组件:

// pages/dashboard.js
import { useEffect, useState } from 'react';
import { useRouter } from 'next/router';

export default function Dashboard({ userRole }) {
  const router = useRouter();
  const [RoleComponent, setRoleComponent] = useState(null);

  useEffect(() => {
    if (!userRole) {
      router.push('/login');
      return;
    }

    // 根据角色动态导入对应组件
    const loadComponent = async () => {
      let component;
      if (userRole === 'admin') {
        component = (await import('../admin/dashboard')).default;
      } else if (userRole === 'employee') {
        component = (await import('../employee/dashboard')).default;
      } else {
        router.push('/403');
        return;
      }
      setRoleComponent(component);
    };

    loadComponent();
  }, [router, userRole]);

  if (!RoleComponent) {
    return <div>加载中...</div>;
  }

  return <RoleComponent />;
}

// 服务端安全获取用户角色(优先用此方式,避免客户端篡改)
export async function getServerSideProps(context) {
  // 从请求的cookie/session中获取用户角色,示例逻辑需根据你的鉴权方式调整
  const userRole = context.req.cookies.userRole;

  if (!userRole) {
    return {
      redirect: {
        destination: '/login',
        permanent: false,
      },
    };
  }

  return {
    props: { userRole },
  };
}

2. 修复客户端Link跳转问题

之前原生Link跳转无效,是因为Next.js客户端路由会优先匹配pages目录结构。现在有了pages/dashboard.js,直接用Link跳转/dashboard即可:

import Link from 'next/link';

// 在任意页面使用
<Link href="/dashboard">
  <a>进入控制台</a>
</Link>

代码中路由跳转直接调用router.push('/dashboard'),无需拼接角色路径。

3. 用Middleware做权限与路由控制

创建middleware.js(Next.js 12+),禁止直接访问带角色标识的路由,同时校验用户权限:

// middleware.js
import { NextResponse } from 'next/server';

export function middleware(request) {
  const userRole = request.cookies.get('userRole')?.value;
  const pathname = request.nextUrl.pathname;

  // 禁止直接访问/admin或/employee开头的路由,强制跳转至/dashboard
  if (pathname.startsWith('/admin/') || pathname.startsWith('/employee/')) {
    // 校验角色是否匹配,不匹配则跳转至403
    if ((pathname.startsWith('/admin/') && userRole !== 'admin') || 
        (pathname.startsWith('/employee/') && userRole !== 'employee')) {
      return NextResponse.redirect(new URL('/403', request.url));
    }
    // 角色匹配则跳转至/dashboard,隐藏角色URL
    return NextResponse.redirect(new URL('/dashboard', request.url));
  }

  // 访问/dashboard时校验用户是否已登录并拥有角色
  if (pathname === '/dashboard' && !userRole) {
    return NextResponse.redirect(new URL('/login', request.url));
  }

  return NextResponse.next();
}

// 指定生效的路由范围
export const config = {
  matcher: ['/dashboard', '/admin/:path*', '/employee/:path*'],
};

4. 可选:保留next.config.js的rewrites(兼容旧路由)

如果需要保留原有/admin/dashboard和/employee/dashboard的服务端映射,可添加rewrites规则确保刷新时正常:

// next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/dashboard',
        destination: '/admin/dashboard',
        has: [{ type: 'cookie', key: 'userRole', value: 'admin' }],
      },
      {
        source: '/dashboard',
        destination: '/employee/dashboard',
        has: [{ type: 'cookie', key: 'userRole', value: 'employee' }],
      },
    ];
  },
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 09:35:16