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

如何在Next.js 13(App目录)中处理服务端授权及角色路由保护?

Next.js 13 App目录架构下的服务端角色授权实现

一、核心逻辑概述

基于服务端HttpOnly Cookie存储的accessToken/refreshToken,在服务端完成令牌解析、用户身份校验及角色权限判断,通过服务端组件或中间件拦截未授权请求,实现路由级别的权限控制。

二、封装服务端工具函数

1. 解析并验证令牌

创建app/lib/auth.ts文件,封装服务端获取用户会话的核心逻辑:

import { cookies } from 'next/headers';
import jwt from 'jsonwebtoken';

// 定义用户信息类型
type User = {
  firstname: string;
  lastname: string;
  roles: string[];
};

type TokenPayload = {
  user: User;
};

export async function getServerSession() {
  const cookieStore = cookies();
  const accessToken = cookieStore.get('accessToken')?.value;

  if (!accessToken) {
    return null;
  }

  try {
    // 从环境变量读取JWT密钥,切勿硬编码
    const decoded = jwt.verify(accessToken, process.env.JWT_SECRET!) as TokenPayload;
    return decoded.user;
  } catch (error) {
    // 处理令牌过期,调用刷新令牌逻辑
    const refreshToken = cookieStore.get('refreshToken')?.value;
    if (refreshToken) {
      // 调用后端接口验证refreshToken并获取新accessToken
      const response = await fetch(`${process.env.API_URL}/refresh-token`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ refreshToken }),
      });

      if (response.ok) {
        const { newAccessToken } = await response.json();
        // 更新accessToken Cookie,配置安全属性
        cookieStore.set('accessToken', newAccessToken, {
          httpOnly: true,
          secure: process.env.NODE_ENV === 'production',
          sameSite: 'strict',
          maxAge: 60 * 15, // 15分钟有效期
          path: '/',
        });
        // 重新解析新令牌返回用户信息
        const decoded = jwt.verify(newAccessToken, process.env.JWT_SECRET!) as TokenPayload;
        return decoded.user;
      }
    }
    return null;
  }
}

// 角色校验工具函数
export function hasRole(user: User | null, requiredRole: string) {
  return user?.roles.includes(requiredRole) ?? false;
}

三、路由权限控制实现

1. 公开路由(如/login)

直接创建app/login/page.tsx,无需权限校验:

export default function LoginPage() {
  return (
    <div>
      <h1>登录页面</h1>
      {/* 登录表单逻辑 */}
    </div>
  );
}

2. 需登录的路由(如/dashboard)

在app/dashboard/page.tsx中通过服务端组件校验会话:

import { getServerSession } from '@/app/lib/auth';
import { redirect } from 'next/navigation';

export default async function DashboardPage() {
  const user = await getServerSession();

  if (!user) {
    // 未登录重定向至登录页
    redirect('/login');
  }

  return (
    <div>
      <h1>欢迎 {user.firstname} 访问仪表盘</h1>
      {/* 仪表盘业务内容 */}
    </div>
  );
}

3. 需特定角色的路由(如/accounting)

在app/accounting/page.tsx中添加角色校验:

import { getServerSession, hasRole } from '@/app/lib/auth';
import { redirect } from 'next/navigation';

export default async function AccountingPage() {
  const user = await getServerSession();

  if (!user || !hasRole(user, 'accounting')) {
    // 无权限重定向至登录页或返回403页面
    redirect('/login');
    // 或直接返回无权限提示:return <div>您无此模块访问权限</div>
  }

  return (
    <div>
      <h1>会计管理模块</h1>
      {/* 会计业务内容 */}
    </div>
  );
}

4. 需admin角色的路由(如/admin)

在app/admin/page.tsx中实现管理员权限校验:

import { getServerSession, hasRole } from '@/app/lib/auth';
import { redirect } from 'next/navigation';

export default async function AdminPage() {
  const user = await getServerSession();

  if (!user || !hasRole(user, 'admin')) {
    redirect('/login');
  }

  return (
    <div>
      <h1>管理员面板</h1>
      {/* 管理员专属内容 */}
    </div>
  );
}

5. 路由组全局校验(可选)

若某组路由需统一权限,可在layout.tsx中批量校验,例如创建app/(protected)/layout.tsx:

import { getServerSession } from '@/app/lib/auth';
import { redirect } from 'next/navigation';

export default async function ProtectedLayout({ children }: { children: React.ReactNode }) {
  const user = await getServerSession();

  if (!user) {
    redirect('/login');
  }

  return <div>{children}</div>;
}

将/dashboard、/accounting等需登录的页面放入app/(protected)目录下,无需每个页面单独校验登录状态。

四、关键注意事项

  • 所有权限校验必须在服务端组件或Middleware中完成,禁止在客户端暴露权限规则。
  • JWT密钥、接口地址等敏感信息必须通过环境变量存储。
  • 确保accessToken和refreshToken的Cookie配置httpOnly、secure(生产环境)、sameSite: strict等安全属性。
  • 无权限请求可根据业务需求返回403页面或重定向至登录页。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 21:10:28