我想提交一份评论。但是在我的verifyToken和verifyUser中间件中,我没有得到值。相反,它说的是值是未定义的,尽管我在控制台中获得了令牌和用户名。
由于我没有在中间件中获得用户信息和令牌,它说我没有授权,并阻止我提交审查。如果我将verifyToken和verifyUser中间件从审查路径中删除,那么它可以正常工作。但如果我添加了它们,那么在终端中会显示:
req.user: undefined
Token: undefined
字符串
虽然我在前端本地存储中获得令牌和用户。
我需要帮助来克服这个问题。感谢是预付款。
中间件:
const jwt = require("jsonwebtoken");
const verifyToken = (req, res, next) => {
console.log("req.user:", req.user);
console.log("req.params.tourId:", req.params.tourId);
const token = req.cookies.accessToken;
console.log("Token received in verifyToken:", token);
console.log("Token:", token);
if (!token) {
return res.status(401).json({
success: false,
message: "You are not authorized",
});
}
try {
const user = jwt.verify(token, process.env.JWT_SECRET);
console.log("Decoded User:", user);
req.user = user;
next();
} catch (error) {
console.error("Token Verification Error:", error);
res.status(401).json({
success: false,
message: "Token is Invalid",
});
}
};
const verifyUser = (req, res, next) => {
console.log("req.user:", req.user);
console.log("req.params.tourId:", req.params.tourId);
if (
req.user &&
(req.user.id === req.params.tourId || req.user.role === "admin")
) {
next();
} else {
return res.status(401).json({
success: false,
message: "You're not authenticated",
});
}
};
const verifyAdmin = (req, res, next) => {
if (req.user.role === "admin") {
next();
} else {
return res.status(401).json({
success: false,
message: "You're not authorized",
});
}
};
module.exports = { verifyToken, verifyAdmin, verifyUser };
型
路线:
const express = require("express");
const router = express.Router();
const { verifyUser, verifyToken } = require("../utils/verifyToken");
const { createReview } = require("../controller/reviewController");
router.post("/:tourId", verifyToken, verifyUser, createReview);
module.exports = router;
型
控制器:
const Review = require("../model/Review");
const Tour = require("../model/Tour");
const createReview = async (req, res) => {
const tourId = req.params.tourId;
const newReview = new Review({ ...req.body });
try {
const savedReview = await newReview.save();
await Tour.findOneAndUpdate(
{ _id: tourId },
{ $push: { reviews: savedReview._id } }
);
res.status(200).json({
success: true,
message: "Review Submitted",
data: savedReview,
});
} catch (error) {
res.status(500).json({
success: false,
message: error.message,
});
console.log(error);
}
};
module.exports = { createReview };
型
TourDetails.jsx:
import React, { useEffect, useRef, useState } from "react";
import "../styles/TourDetails.css";
import { Container, Row, Col, Form, ListGroup } from "reactstrap";
import { useParams } from "react-router-dom";
import calculateAvgRating from "../utils/averageRating";
import { AiFillStar, AiOutlineStar } from "react-icons/ai";
import { MdLocationPin } from "react-icons/md";
import { HiUserGroup } from "react-icons/hi";
import { FaDollarSign } from "react-icons/fa";
import { GrLocation } from "react-icons/gr";
import { RiPinDistanceFill } from "react-icons/ri";
import avatar from "../assets/tour-images/avatar.jpg";
import Booking from "../components/Booking/Booking";
import { useSelector, useDispatch } from "react-redux";
import { getSingleTour } from "../redux/action/tourAction";
import { server } from "../server";
import axios from "axios";
import { toast } from "react-toastify";
const TourDetails = () => {
const { id } = useParams();
const dispatch = useDispatch();
const reviewsMsgRef = useRef("");
const [userRating, setUserRating] = useState(0);
const [user, setUser] = useState({});
const [submittedReview, setSubmittedReview] = useState(null);
const [isLoggedIn, setIsLoggedIn] = useState(
!!localStorage.getItem("accessToken")
);
// Fetch single tour when the component mounts
useEffect(() => {
dispatch(getSingleTour(id));
window.scrollTo(0, 0);
}, [dispatch, id]);
useEffect(() => {
setIsLoggedIn(!!localStorage.getItem("accessToken"));
const storedUser = JSON.parse(localStorage.getItem("user"));
if (storedUser) {
setUser(storedUser);
}
console.log(user);
}, []);
const { tour, isLoading, error } = useSelector((state) => state.tour);
if (isLoading) {
return <div>Loading...</div>;
}
if (error) {
return <div>{error}</div>;
}
if (!tour) {
return <div>Tour not found.</div>;
}
const {
photo,
title,
desc,
price,
reviews,
address,
city,
distance,
maxGroupSize,
} = tour.data;
const { totalRating, avgRating } = calculateAvgRating(reviews);
const options = { day: "numeric", month: "long", year: "numeric" };
const handleStarClick = (rating) => {
setUserRating(rating);
};
const isRatingSelected = (rating) => rating <= userRating;
const handleSubmitReview = async (e) => {
e.preventDefault();
const reviewText = reviewsMsgRef.current.value;
const accessToken = localStorage.getItem("accessToken");
if (!accessToken) {
toast.error("Please login first to submit a review.");
return;
}
try {
const reviewObj = {
username: user.name,
reviewText,
rating: userRating,
};
const res = await axios.post(`${server}/reviews/${id}`, reviewObj, {
withCredentials: true,
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
// Store the submitted review data in the component state
setSubmittedReview(res.data.data);
toast.success("Review submitted successfully");
console.log("Review submitted successfully:", res.data);
} catch (error) {
toast.error("Error submitting review");
console.log(error);
}
};
return (
<section>
<Container>
<Row>
<Col lg="8">
<div className="tour_content">
<img src={photo} alt="photo" />
<div className="tour_info">
<h2>{title}</h2>
<div className="d-flex align-items-center gap-5">
{avgRating > 0 ? (
<span className="tour_rating d-flex align-items-center gap-1">
<AiFillStar className="tour_icon" />
{avgRating}
<span>({reviews?.length})</span>
</span>
) : (
<span className="tour_rating">Not Rated</span>
)}
<span>
<GrLocation className="tour_icon" />
{address}
</span>
</div>
<div className="tour_extra-details d-flex align-items center">
<span>
<MdLocationPin className="tour_icon" />
{city}
</span>
<span>
<RiPinDistanceFill className="tour_icon" />
{distance} k/m
</span>
<span>
<FaDollarSign className="tour_icon" />$ {price}/per person
</span>
<span>
<HiUserGroup className="tour_icon" />
{maxGroupSize} people
</span>
</div>
<h5>Description</h5>
<p>{desc}</p>
</div>
<div className="tour_reviews mt-4">
<h4>Reviews ({reviews?.length} reviews)</h4>
<Form onSubmit={handleSubmitReview}>
<div className="rating_group d-flex align-items-center gap-3 mb-4">
{[1, 2, 3, 4, 5].map((rating) => (
<span
key={rating}
onClick={() => handleStarClick(rating)}
>
{isRatingSelected(rating) ? (
<AiFillStar />
) : (
<AiOutlineStar />
)}
</span>
))}
</div>
<div className="review_input d-flex align-items-center">
<input
type="text"
ref={reviewsMsgRef}
placeholder="Share your thoughts"
required
/>
<button
className="btn primary_btn text-white"
type="submit"
>
Submit
</button>
</div>
</Form>
<ListGroup className="user_reviews">
{submittedReview && (
<div className="review_item">
<img src={avatar} alt="avatar" />
<div className="w-100">
<div className="d-flex align-items-center justify-content-between">
<div>
<h5>{submittedReview.username}</h5>
<p>
{new Date().toLocaleDateString("en-US", options)}
</p>
</div>
<span className="d-flex align-items-center">
<AiFillStar className="review_icon" />5
</span>
</div>
<h6>{submittedReview.reviewText}</h6>
</div>
</div>
)}
{reviews.map((review, index) => (
<div className="review_item" key={index}>
<img src={avatar} alt="avatar" />
<div className="w-100">
<div className="d-flex align-items-center justify-content-between">
<div>
<h5>{review.username}</h5>
<p>
{new Date("08-28-2023").toLocaleDateString(
"en-US",
options
)}
</p>
</div>
<span className="d-flex align-items-center">
<AiFillStar className="review_icon" />5
</span>
</div>
<h6>Amazing Tour</h6>
</div>
</div>
))}
</ListGroup>
</div>
</div>
</Col>
<Col lg="4">
<Booking tour={tour} avgRating={avgRating} />
</Col>
</Row>
</Container>
</section>
);
};
export default TourDetails;
型
1条答案
按热度按时间2cmtqfgy1#
编辑
看起来你在前端的Authorization头上发送访问令牌,但试图从
verifyToken
中间件函数中的cookie中读取。请记住,在您的axios请求配置对象中设置的withCredentials
属性不会自动发送存储在localStorage
对象中的数据,它只会发送为您当前浏览会话存储的相关cookie。只要在请求的Authorization
头中发送了一个有效的会话jwt,下面的代码就可以帮助您通过验证。字符串
原文回答:
我没有看到任何对
verifyToken
函数的调用,该函数应该设置req.user
对象,所以看起来你需要替换:型
与:
型
这将首先调用
verifyToken
,如果验证成功,它将设置req.user
对象,然后调用下一个中间件函数,在本例中是verifyUser
。