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

Next.js 14房产应用:管理端与用户端页面权限控制及目录结构设计

Next.js 14 房产应用权限控制实现方案

推荐目录结构

/app
  /auth
    /login
      page.tsx
  /dashboard  # 管理端页面
    layout.tsx
    /properties
      page.tsx
    /users
      page.tsx
  /client     # 用户端页面
    layout.tsx
    /home
      page.tsx
    /property-details
      [id]
        page.tsx
  /_components
    /auth
      SessionProviderWrapper.tsx
  middleware.ts
  layout.tsx
/lib
  /auth
    session.ts  # 会话处理工具函数

核心实现步骤

1. 实现会话与角色判断工具函数

在/lib/auth/session.ts中编写工具函数,用于获取当前用户会话和判断角色:

import { cookies } from 'next/headers';

// 假设登录后在cookie中存储用户信息,包含role字段('user' | 'admin')
export async function getCurrentUser() {
  const cookieStore = cookies();
  const userCookie = cookieStore.get('user');
  
  if (!userCookie) return null;
  
  try {
    return JSON.parse(userCookie.value);
  } catch (err) {
    return null;
  }
}

export async function isAdmin() {
  const user = await getCurrentUser();
  return user?.role === 'admin';
}

export async function isLoggedIn() {
  const user = await getCurrentUser();
  return !!user;
}

2. 编写 Middleware 实现权限拦截

在项目根目录的middleware.ts中编写核心权限控制逻辑:

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { getCurrentUser } from './lib/auth/session';

export async function middleware(request: NextRequest) {
  const path = request.nextUrl.pathname;
  
  // 定义路由规则
  const isAuthRoute = path.startsWith('/auth/login');
  const isDashboardRoute = path.startsWith('/dashboard');
  const isClientRoute = path.startsWith('/client');
  
  const user = await getCurrentUser();
  
  // 未登录用户处理
  if (!user) {
    // 非登录页跳转登录
    if (!isAuthRoute) {
      return NextResponse.redirect(new URL('/auth/login', request.url));
    }
    return NextResponse.next();
  }
  
  // 已登录用户访问登录页,跳转对应首页
  if (isAuthRoute) {
    return user.role === 'admin' 
      ? NextResponse.redirect(new URL('/dashboard', request.url))
      : NextResponse.redirect(new URL('/client/home', request.url));
  }
  
  // 普通用户拦截管理端路由
  if (isDashboardRoute) {
    if (user.role !== 'admin') {
      return NextResponse.redirect(new URL('/client/home', request.url));
    }
    return NextResponse.next();
  }
  
  // 用户端路由放行(管理员也可访问,需限制可调整)
  if (isClientRoute) {
    return NextResponse.next();
  }
  
  // 其他路由默认放行
  return NextResponse.next();
}

// 指定Middleware生效的路由(排除静态资源和API)
export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};

3. 布局组件配合权限控制

  • 根布局(/app/layout.tsx):全局引入会话提供者,确保页面能获取用户信息:
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import SessionProviderWrapper from './_components/auth/SessionProviderWrapper';

const inter = Inter({ subsets: ['latin'] });

export const metadata: Metadata = {
  title: '房产应用',
  description: '房产管理与用户服务平台',
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="zh-CN">
      <body className={inter.className}>
        <SessionProviderWrapper>{children}</SessionProviderWrapper>
      </body>
    </html>
  );
}
  • 管理端布局(/app/dashboard/layout.tsx):双重验证权限,渲染管理员专属导航:
import { getCurrentUser } from '@/lib/auth/session';

export default async function DashboardLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const user = await getCurrentUser();
  
  // 防止middleware被绕过,二次验证权限
  if (user?.role !== 'admin') {
    return <div>无权限访问</div>;
  }
  
  return (
    <div className="dashboard-container">
      <nav>管理员导航:房产管理 | 用户管理</nav>
      <main>{children}</main>
    </div>
  );
}
  • 用户端布局(/app/client/layout.tsx):渲染用户专属导航:
import { getCurrentUser } from '@/lib/auth/session';

export default async function ClientLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  const user = await getCurrentUser();
  
  return (
    <div className="client-container">
      <nav>用户导航:首页 | 房产列表 | 我的收藏</nav>
      <main>{children}</main>
    </div>
  );
}

4. 登录页面示例(/app/auth/login/page.tsx)

登录成功后设置用户cookie,包含角色信息:

'use client';

import { useState } from 'react';
import { cookies } from 'next/headers';
import { useRouter } from 'next/navigation';

export default function LoginPage() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const router = useRouter();

  const handleLogin = async (e: React.FormEvent) => {
    e.preventDefault();
    
    // 模拟登录请求,实际替换为后端接口
    const mockUser = email.includes('admin') 
      ? { id: 1, email, role: 'admin' }
      : { id: 2, email, role: 'user' };
    
    // 设置安全cookie,生产环境需配置secure: true
    cookies().set('user', JSON.stringify(mockUser), {
      httpOnly: true,
      maxAge: 60 * 60 * 24, // 有效期1天
      path: '/',
    });
    
    // 根据角色跳转对应页面
    router.push(mockUser.role === 'admin' ? '/dashboard' : '/client/home');
  };

  return (
    <div className="login-container">
      <form onSubmit={handleLogin}>
        <input
          type="email"
          placeholder="邮箱"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          required
        />
        <input
          type="password"
          placeholder="密码"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          required
        />
        <button type="submit">登录</button>
      </form>
    </div>
  );
}

关键注意事项

  • Cookie安全:生产环境务必开启secure: true和sameSite: 'strict',防范CSRF攻击。
  • 双重验证:布局和页面中加入权限判断,避免Middleware被绕过。
  • 会话刷新:使用JWT时需处理token过期自动刷新逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 10:13:09