英文:
User is not authenticated jswtoken
问题
我已经创建了一个登录页面和一个关于页面,只有当用户登录后才能访问关于页面。我正在尝试使用在登录时生成的令牌来验证用户,但即使使用正确的凭据登录后,令牌仍未得到验证。我不知道问题在哪里?
这是我的登录和令牌生成方法的代码:
const express = require("express");
const { default: mongoose } = require("mongoose");
const router = express.Router();
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
require("../db/conn");
const User = require("../model/userSchema");
const cookieParser = require('cookie-parser');
const Authenticate = require("../middleware/authenticate");
router.use(cookieParser());
// 登录路由
router.post("/signin", (req, res)=>{
if(!req.body.email || !req.body.password){
return res.status(400).json({error: "请填写所需数据"});
}else{
bcrypt.hash(req.body.password, 12, function (err, hash) {
User.findOne({email: req.body.email}, function (err, foundUser) {
if(err){
console.log(err);
}else{
if(foundUser){
bcrypt.compare(req.body.password, foundUser.password, function (err, result) {
if(result){
return res.json({message: "成功登录"})
}else{
return res.json({message: "密码错误"});
}
});
const email = req.body.email;
const token = jwt.sign(
{ user_id: foundUser._id, email },
process.env.TOKEN_KEY,
{
expiresIn: "720h",
}
);
foundUser.tokens = foundUser.tokens.concat({token: token});
foundUser.save();
// res.status(200).json(foundUser);
console.log(foundUser);
}else{
return res.status(400).json({message: "用户未找到"});
};
}
})
})
}
});
// 关于我们页面
router.get("/about", Authenticate, function (req, res) {
console.log("about running");
res.send(req.rootUser);
});
module.exports = router;
这是用于验证用户的代码:
require("dotenv").config({path: "./config.env"});
const jwt = require("jsonwebtoken");
const User = require("../model/userSchema");
const Authenticate = async(req, res, next) => {
try {
const token = req.cookies.jwtoken;
const verifyToken = jwt.verify(token, process.env.TOKEN_KEY);
const rootUser = await User.findOne({ _id: verifyToken._id, "tokens.token": token});
if(!rootUser) {
throw new Error("用户未找到")
}
req.token = token;
req.rootUser = rootUser;
req.userID = rootUser._id;
next();
} catch (err) {
console.log(err);
return res.status(401).send("未授权:未提供令牌");
}
}
module.exports = Authenticate;
这是基于React的代码,用于根据用户的真实性来显示关于页面:
const navigate = useNavigate();
const callAboutPage = async() => {
try {
const res = await fetch("/about",{
method: "GET",
headers: {
Accept: "application/json",
"Content-Type" : "application/json"
},
credentials: "include"
});
const data = await res.json();
console.log(data);
if(!res.status === 200){
const error = new Error(res.error);
throw error;
}
} catch (err) {
console.log(err);
navigate("/login");
}
}
英文:
I have created a login page and a about page the user will only access the about page if the user is logged in.
I am trying to authenticate the user by using the tokens generated while signing in, but the token is not getting authenticated even after signing in with the correct credentials. I don't know what is the problem?
This is code to my sign-in and token generating method
const express = require("express");
const { default: mongoose } = require("mongoose");
const router = express.Router();
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
require("../db/conn");
const User = require("../model/userSchema");
const cookieParser = require('cookie-parser');
const Authenticate = require("../middleware/authenticate");
router.use(cookieParser());
//LOgin route
router.post("/signin", (req, res)=>{
if(!req.body.email || !req.body.password){
return res.status(400).json({error: "Plz fill the required data"});
}else{
bcrypt.hash(req.body.password, 12, function (err, hash) {
User.findOne({email: req.body.email}, function (err, foundUser) {
if(err){
console.log(err);
}else{
if(foundUser){
bcrypt.compare(req.body.password, foundUser.password, function (err, result) {
if(result){
return res.json({message: "successfully log in"})
}else{
return res.json({message: "incorrect password"});
}
});
const email = req.body.email;
const token = jwt.sign(
{ user_id: foundUser._id, email },
process.env.TOKEN_KEY,
{
expiresIn: "720h",
}
);
foundUser.tokens = foundUser.tokens.concat({token: token});
foundUser.save();
// res.status(200).json(foundUser);
console.log(foundUser);
}else{
return res.status(400).json({message: "user not found"});
};
}
})
})
}
});
//about us page
router.get("/about", Authenticate, function (req, res) {
console.log("about running");
res.send(req.rootUser);
});
module.exports = router;
this is the code to authenticate the user
require("dotenv").config({path: "./config.env"});
const jwt = require("jsonwebtoken");
const User = require("../model/userSchema");
const Authenticate = async(req, res, next) =>{
try {
const token = req.cookies.jwtoken;
const verifyToken = jwt.verify(token, process.env.TOKEN_KEY);
const rootUser = await User.findOne({ _id: verifyToken._id, "tokens.token": token});
if(!rootUser) {
throw new Error("User not found")
}
req.token = token;
req.rootUser = rootUser;
req.userID = rootUser._id;
next();
} catch (err) {
console.log(err);
return res.status(401).send("Unauthorized: No token provided");
}
}
module.exports = Authenticate;
<!-- end snippet -->
This is react based code of: About-page to display it or not based on user's authenticity.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const navigate = useNavigate();
const callAboutPage = async() =>{
try {
const res = await fetch("/about",{
method: "GET",
headers: {
Accept: "application/json",
"Content-Type" : "application/json"
},
credentials: "include"
});
const data = await res.json();
console.log(data);
if(!res.status === 200){
const error = new Error(res.error);
throw error;
}
} catch (err) {
console.log(err);
navigate("/login");
}
}
答案1
得分: 0
尝试使用app.use
代替router.use
来使用cookieParser
(app
是Express实例)
示例:
const app = express();
app.use(cookieParser());
并尝试将其放在index.js
或app.js
文件中的服务器监听之前。
希望这有所帮助。
英文:
router.use(cookieParser());
Try to use cookieParser with app.use instead. (app from express instense)
Expample:
const app = express();
app.use(cookieParser());
and try to put it before server listening in index.js or app.js file.
Hope it help.
答案2
得分: 0
以下是翻译好的部分:
"As said in the comment looks like there is an issue on the process for setting up the jwtoken, and when you sign in, you just need to find the user and compare the password, there is no need to do the hash with Bcrypt, since you're not registering a new user. For example, I will use Async/await instead of a callback function, in order for you to read it much more easily:
// 登录路由
router.post("/signin", async (req, res) => {
const { reqEmail, reqPassword } = req.body; // 解构以减少下一步的写作量
if (!reqEmail || !reqPassword) {
return res.status(400).json({ message: "请填写所需数据" });
}
try {
const foundUser = await User.findOne({ email: reqEmail });
if (!foundUser) {
return res.status(400).json({ message: "用户名或密码错误!" });
}
const result = await bcrypt.compare(reqPassword, foundUser.password);
if (!result) {
return res.json({ message: "用户名或密码错误!" });
} else {
const accessToken = jwt.sign(
{ user_id: foundUser._id, email: foundUser.email },
process.env.TOKEN_KEY,
{ expiresIn: "720h" }
);
// 我不确定你在这里要做什么,如果是我的话,我会在身份验证中设置cookie,因为你已经在身份验证中这样做了。
res.cookie("jwt", accessToken, {
maxAge: 60000, // 60秒用于测试
httpOnly: true,
sameSite: false, // 仅在开发中为false
secure: false, // 仅在开发中为false
});
res.status(200).json(foundUser);
}
} catch (error) {
return res.status(500).json({ message: `${error}` });
}
}
然后是身份验证中间件:
// ...
const Authenticate = (req, res, next) => {
const accessToken = req.cookies.jwt;
if (!accessToken) {
return res.status(401).json({ error: "未经授权:未提供令牌" });
}
try {
const user = jwt.verify(accessToken, process.env.TOKEN_KEY);
if (user) {
req.user = user;
return next();
}
} catch (error) {
return res.status(403).json({ error: "禁止令牌错误" });
}
}
关于页面组件目前很简单,因为你不管理任何状态
const navigate = useNavigate();
const callAboutPage = async () => {
try {
const res = await fetch("/about", {
headers: {
"Content-Type": "application/json"
},
credentials: "include"
});
if (res.status === 200) {
const data = await res.json();
// 设置用于渲染的状态
console.log(data);
} else {
// 你也可以创建一个状态来捕获来自后端的错误消息,在这种情况下,响应json应该移至上面的if语句之前。
throw new Error("您必须登录才能访问");
// 然后你可以显示这个错误消息,或者使用此块的状态来自后端,以及catch块
// 导航到/login
}
} catch (err) {
console.log(err);
navigate("/login");
}
}"
英文:
As said in the comment looks like there is a issue on the process for setting up the jwtoken, and when you sign in, you just need to find the user and compare the password, there is no need to do the hash with Bcrypt, since you're not registing new user, for example, i will use Async/await instead of callback function, in order for you to read it much more easier:
//Login route
router.post("/signin", async (req, res)=> {
const { reqEmail, reqPassword } = req.body; //destructuring so less thing to write at the next step
if(!reqEmail || !reqPassword) {
return res.status(400).json({message: "Plz fill the required data"});
}
try {
const foundUser = await User.findOne({email: reqEmail})
if(!foundUser) {
return res.status(400).json({message: "Wrong username or password!"})
}
const result = await bcrypt.compare(reqPassword, foundUser.password);
if(!result){
return res.json({message: "Wrong username or password!"})
} else {
const accessToken = jwt.sign(
{ user_id: foundUser._id, email: foundUser.email},
process.env.TOKEN_KEY,
{ expiresIn: "720h",}
);
// I am confuse what are you trying to do here, in your place I would set up on the cookie since you do that on your authentification.
res.cookie("jwt", accessToken, {
maxAge: 60000, // 60 sec for testing
httpOnly: true,
sameSite: false, //false only for dev
secure: false, //false only for dev
})
res.status(200).json(foundUser);
};
} catch (error) {
return res.status(500).json({message: `${error}`})
}
Than the authentification middleware :
// ...
const Authenticate = (req, res, next) => {
const accessToken = req.cookies.jwt
if(!accessToken) {
return res.status(401).json({error: "Unauthorized: No token provided"});
}
try {
const user = jwt.verify(accessToken, process.env.TOKEN_KEY)
if(user) {
req.user = user
return next();
}
} catch (error) {
return res.status(403).json({error: "Forbidden token error"})
}
}
about page component it's simple for now since you don't manage any state
const navigate = useNavigate();
const callAboutPage = async() =>{
try {
const res = await fetch("/about",{
headers: {
"Content-Type": "application/json"
},
credentials: "include"
});
if(res.status === 200){
const data = await res.json();
// set up the state for rendering
console.log(data);
} else {
// you can also create a state to catch the error message from the backend, in this case the response json should be move to above the if statement.
throw new Error("You must log in to get access")
// than you can display this error message, or from the backend using state for this bloc, and the catch bloc
// navigate to /login
}
} catch (err) {
console.log(err);
navigate("/login");
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论