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

基于Node、React、MongoDB实现认证用户类型识别方案咨询

当然可以用JWT来实现这个需求!我来给你拆解下基于Node.js + React + MongoDB的完整方案,分后端和前端两部分一步步讲:

后端实现(Node.js + MongoDB)

1. 定义用户模型

首先在MongoDB里创建用户集合,需要包含role字段来区分普通用户和管理员,用Mongoose的话可以这么写:

const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  email: { type: String, required: true, unique: true },
  password: { type: String, required: true },
  // 限定角色只能是user或admin,默认普通用户
  role: { type: String, enum: ['user', 'admin'], default: 'user' }
});

module.exports = mongoose.model('User', userSchema);

2. JWT生成与登录接口

先安装依赖:npm install jsonwebtoken bcryptjs,bcrypt用来加密存储密码,避免明文泄露。

然后写登录接口,验证用户身份后,把role字段放进JWT的payload里:

const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const User = require('../models/User');

// 登录接口
exports.login = async (req, res) => {
  try {
    const { email, password } = req.body;
    // 查找用户
    const user = await User.findOne({ email });
    if (!user) return res.status(400).json({ message: '用户不存在' });
    
    // 验证密码
    const isPasswordMatch = await bcrypt.compare(password, user.password);
    if (!isPasswordMatch) return res.status(400).json({ message: '密码错误' });

    // 生成JWT,包含用户ID和角色
    const token = jwt.sign(
      { userId: user._id, role: user.role },
      process.env.JWT_SECRET, // 密钥存环境变量,绝对不能硬编码
      { expiresIn: '7d' } // 按需设置过期时间
    );

    // 返回token和基本用户信息
    res.json({
      token,
      user: { id: user._id, email: user.email, role: user.role }
    });
  } catch (err) {
    res.status(500).json({ message: '服务器内部错误' });
  }
};

3. JWT验证与权限中间件

写一个中间件用来验证请求中的JWT,并解析出用户信息,后续接口用这个中间件保护:

exports.protect = async (req, res, next) => {
  let token;
  // 从请求头的Authorization字段获取token(格式:Bearer <token>)
  if (req.headers.authorization?.startsWith('Bearer')) {
    token = req.headers.authorization.split(' ')[1];
  }

  if (!token) return res.status(401).json({ message: '未授权,请先登录' });

  try {
    // 验证token并解析payload
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    // 把用户信息挂载到req对象上,方便后续接口使用
    req.user = await User.findById(decoded.userId).select('-password');
    next();
  } catch (err) {
    res.status(401).json({ message: 'Token无效或已过期' });
  }
};

如果需要单独限制管理员才能访问的接口,再写一个管理员权限中间件:

exports.adminOnly = (req, res, next) => {
  if (req.user?.role === 'admin') {
    next();
  } else {
    res.status(403).json({ message: '无管理员权限' });
  }
};

然后就能用这些中间件保护接口了:

// 普通用户和管理员都能访问的接口
router.get('/profile', authController.protect, userController.getProfile);
// 仅管理员能访问的接口
router.get('/all-users', authController.protect, authController.adminOnly, userController.getAllUsers);
前端实现(React)

1. 登录状态与角色管理

用Context API来全局管理用户登录状态和角色信息(用Redux也可以,看你技术选型):

import { createContext, useContext, useState, useEffect } from 'react';

const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  // 页面加载时从localStorage恢复登录状态
  useEffect(() => {
    const storedUser = localStorage.getItem('user');
    if (storedUser) setUser(JSON.parse(storedUser));
    setLoading(false);
  }, []);

  // 登录函数
  const login = async (email, password) => {
    try {
      const res = await fetch('/api/auth/login', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ email, password })
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.message);

      setUser(data.user);
      localStorage.setItem('user', JSON.stringify(data.user));
      localStorage.setItem('token', data.token);
    } catch (err) {
      alert(err.message);
    }
  };

  // 登出函数
  const logout = () => {
    setUser(null);
    localStorage.removeItem('user');
    localStorage.removeItem('token');
  };

  return (
    <AuthContext.Provider value={{ user, login, logout, loading }}>
      {!loading && children}
    </AuthContext.Provider>
  );
};

export const useAuth = () => useContext(AuthContext);

记得在App.js里用AuthProvider包裹所有组件,让全局都能访问到登录状态。

2. 路由权限控制

用React Router实现路由保护,区分普通用户和管理员路由:

私有路由(需登录)

import { Navigate } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';

const PrivateRoute = ({ children }) => {
  const { user } = useAuth();
  if (!user) return <Navigate to="/login" replace />;
  return children;
};

export default PrivateRoute;

管理员路由(需管理员权限)

import { Navigate } from 'react-router-dom';
import { useAuth } from '../contexts/AuthContext';

const AdminRoute = ({ children }) => {
  const { user } = useAuth();
  if (!user || user.role !== 'admin') return <Navigate to="/" replace />;
  return children;
};

export default AdminRoute;

然后配置路由:

import { Routes, Route } from 'react-router-dom';
import Login from './pages/Login';
import Home from './pages/Home';
import AdminDashboard from './pages/AdminDashboard';
import PrivateRoute from './components/PrivateRoute';
import AdminRoute from './components/AdminRoute';

const AppRoutes = () => {
  return (
    <Routes>
      <Route path="/login" element={<Login />} />
      {/* 普通用户和管理员都能访问的私有路由 */}
      <Route path="/" element={
        <PrivateRoute>
          <Home />
        </PrivateRoute>
      } />
      {/* 仅管理员能访问的路由 */}
      <Route path="/admin" element={
        <AdminRoute>
          <AdminDashboard />
        </AdminRoute>
      } />
    </Routes>
  );
};

export default AppRoutes;

3. 页面内容动态渲染

在组件里通过useAuth获取用户角色,动态渲染对应内容:

import { useAuth } from '../contexts/AuthContext';

const Home = () => {
  const { user } = useAuth();
  return (
    <div className="home">
      <h1>欢迎回来,{user.email}</h1>
      {/* 管理员专属内容 */}
      {user.role === 'admin' && (
        <div className="admin-section">
          <p>你是管理员,拥有全部权限</p>
          <button>前往用户管理面板</button>
        </div>
      )}
      {/* 普通用户专属内容 */}
      {user.role === 'user' && (
        <p>你可以查看和编辑个人信息</p>
      )}
    </div>
  );
};

export default Home;

4. 请求自动携带JWT

封装一个带认证的fetch工具函数,每次请求自动把token放到请求头:

const fetchWithAuth = async (url, options = {}) => {
  const token = localStorage.getItem('token');
  const headers = {
    'Content-Type': 'application/json',
    ...options.headers
  };
  if (token) headers.Authorization = `Bearer ${token}`;
  
  return fetch(url, { ...options, headers });
};

// 使用示例
const fetchProfile = async () => {
  const res = await fetchWithAuth('/api/users/profile');
  const data = await res.json();
  // 处理数据
};
注意事项
  • JWT密钥一定要存在环境变量里,绝对不能硬编码到代码中
  • 用户密码必须用bcrypt加密存储,禁止明文存储
  • 前端用localStorage存token有XSS风险,若要更安全可以考虑用HttpOnly Cookie(需要后端配置跨域Cookie)
  • 后端要配置CORS,允许前端跨域请求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 12:17:06