直接通过 URL 访问受保护的路由时出现“访问被拒绝:未提供令牌”错误,即使已登录(React、Express、JWT)

问题描述 投票:0回答:1

我正在开发一个 Web 应用程序,使用 React 和 Vite 作为前端,Express 作为后端,MongoDB 作为数据库。我有几个受保护的路由,例如 /employees 和 /clients。这些路由要求用户登录并通过 JWT 令牌进行身份验证。

问题:

当我使用网页上的链接导航到这些路线时,如果我登录了,一切都会正常。但是,如果我尝试通过在地址栏中输入 URL 直接访问这些路线,则会收到以下错误:

{"error":"Access denied: No token provided"}

即使我登录了,也会发生这种情况,并且令牌存储在 localStorage 中。我的登录逻辑工作正常,并且在通过链接导航时,令牌会在请求标头中发送。

后端(Express):

auth.js

const express = require("express");
const router = express.Router();
const User = require("../models/User");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");

const JWT_SECRET = process.env.JWT_SECRET;

// Login route
router.post("/login", async (req, res) => {
  const { username, password } = req.body;
  try {
    const user = await User.findOne({ username });
    if (!user) return res.status(400).send({ error: "Invalid credentials" });

    const isMatch = await bcrypt.compare(password, user.password);
    if (!isMatch) return res.status(400).send({ error: "Invalid credentials" });

    const token = jwt.sign({ id: user._id }, JWT_SECRET, { expiresIn: "7d" });
    res.send({ token });
  } catch (err) {
    res.status(500).send({ error: "Internal server error" });
  }
});

module.exports = router;

authMiddleware.js

const jwt = require("jsonwebtoken");
const JWT_SECRET = process.env.JWT_SECRET;

const authMiddleware = (req, res, next) => {
  let token;
  const authHeader = req.header("Authorization");

  if (authHeader && authHeader.startsWith("Bearer ")) {
    token = authHeader.replace("Bearer ", "");
  }

  if (!token) {
    console.log("No token provided");
    return res.status(401).send({ error: "Access denied: No token provided" });
  }

  try {
    const decoded = jwt.verify(token, JWT_SECRET);
    req.user = decoded;
    next();
  } catch (err) {
    console.log("Invalid token:", err.message);
    res.status(401).send({ error: "Invalid token" });
  }
};

module.exports = authMiddleware;

前端(反应)

App.jsx:

import { useEffect } from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import axios from 'axios';

import PrivateRoute from './components/PrivateRoute';
import EmployeesPage from './components/EmployeesPage';
import ClientsPage from './components/ClientsPage';
import LoginPage from './components/LoginPage';

const App = () => {
  useEffect(() => {
    const token = localStorage.getItem('token');
    if (token) {
      axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
    }
  }, []);

  return (
    <Router>
      <Routes>
        <Route path="/login" element={<LoginPage />} />
        <Route path="/employees" element={<PrivateRoute element={<EmployeesPage />} />} />
        <Route path="/clients" element={<PrivateRoute element={<ClientsPage />} />} />
      </Routes>
    </Router>
  );
};

export default App;

PrivateRoute.jsx:

import { Navigate } from 'react-router-dom';

const PrivateRoute = ({ element, redirectTo = '/login' }) => {
  const token = localStorage.getItem('token');

  if (!token) {
    return <Navigate to={redirectTo} />;
  }

  return element;
};

export default PrivateRoute;

我尝试过的:

  • 我已确认登录后令牌已存储在 localStorage 中。
  • 我在加载应用程序时使用令牌在 Axios 中设置默认的授权标头。
  • 通过应用程序内的链接导航时,受保护的路线可以正常工作

预期行为:

当直接通过地址栏访问 URL 时,应用程序应识别来自 localStorage 的令牌,将其发送到标头中,并允许访问受保护的路由。

问题:

为什么我在通过地址栏直接访问路由时会收到“访问被拒绝:未提供令牌”错误,即使我已登录?在这些情况下如何确保令牌正确发送?

任何帮助或指导将不胜感激!

reactjs express authentication jwt vite
1个回答
0
投票

同意@C3roe的评论。

为了实现所需的功能,您可能需要使用 cookie 来代替存储对象或 localStorage。

Cookie 是环境权威的一种形式。服务器设置域属性来指定 cookie 将发送到的主机。当域属性与源服务器匹配时,用户代理将在发出 HTTP 请求时包含 cookie。这些 HTTP 请求可以用于嵌入内容,例如来自其他站点的图像和视频、获取请求以及顶级导航。

但是,存储对象或本地存储不能包含在顶级导航中,这是您现在遇到的困难。

© www.soinside.com 2019 - 2024. All rights reserved.