尝试使用有效令牌直接访问页面时,JWT 身份验证不起作用;将在登录时开始工作。反应/节点/快递
Posted
技术标签:
【中文标题】尝试使用有效令牌直接访问页面时,JWT 身份验证不起作用;将在登录时开始工作。反应/节点/快递【英文标题】:JWT Authentication not working when trying to access a page directly with valid token; will work when starting at login. React/Node/Express 【发布时间】:2021-01-17 09:36:45 【问题描述】:我有一个生成 JWT 的登录,然后是一个中间件,用于验证从标头中获取的令牌。令牌还按照建议存储在客户端的 localStorage 中。问题是登录正常工作,“已验证”返回true,但尝试时
重新加载页面或
使用有效令牌直接访问仪表板,而不是从登录页面访问。 错误发生在邮递员中的“jwtExpired”或“未授权(授权不是jwt令牌)”(见下文)
当使用邮递员并运行静态文件时,就会出现这种行为;运行“npm start”时不会发生。我将复制邮递员中生成的令牌并将其放在标题中并尝试获取“/dashboard”并给我留下同样的错误。此外,它是 console.error 的“jwtExpired”。我已经检查并重新检查了令牌,它是正确的。在许多 SO 问题和文档之后,我必须在服务器端遗漏一些东西。错误出现在这个中间件文件authorization.js中:
const jwt = require("jsonwebtoken")
require("dotenv").config()
module.exports = async (req, res, next) =>
try
// step 1 destructure
const jwtToken = req.header("token")
if(!jwtToken)
return res.status(403).json("Not Authorized (authorization not jwt Token)")
/////////////////This is where the program stops when reloaded or accessed directly
// step 2 check if the token is valid
const payload = jwt.verify(jwtToken, process.env.jwtSecret)
// step 3 gives access as req.user
req.user = payload.user
next()
catch (err)
console.error(err.message)
return res.status(403).json("Not Authorized (authorization catch)")
从我的 server.js 文件开始:
const express= require("express")
const app = express()
const cors = require("cors")
const path = require('path')
// middleware
app.use(express.json())
app.use(cors())
// ROUTES
// register and login
app.use("/auth", require("./routes/jwtAuth"))
app.use("/dashboard", require("./routes/dashboard"))
app.use("/", express.static(path.join(__dirname, 'client/build')))
app.get("*", (req, res) =>
res.sendFile(path.join(__dirname, "client/build/index.html"));
);
const PORT = process.env.PORT || 5000
app.listen(PORT, () =>
console.log(`Server is running on port $PORT`)
)
使用 jwtAuth.js 登录、注册和/或检查授权(validInfo 仅检查正确的电子邮件地址):
const router = require("express").Router()
const pool = require("../db")
const bcrypt = require("bcrypt")
const jwtGenerator = require("../utils/jwtGenerator")
const validInfo = require("../middleware/validInfo")
const authorization = require("../middleware/authorization")
// registering
router.post("/register", validInfo, async(req, res) =>
try
// step1 destructure
const name, email, password = req.body
// step2 check if the user exists
const user = await pool.query("SELECT * FROM users WHERE user_email=$1", [email])
if(user.rows.length >0)
return res.status(401).json("User already exists; email is already registered with the
database")
// step3 bcrypt the user password for db
const saltRound = 10;
const salt = await bcrypt.genSalt(saltRound)
const bcryptPassword = await bcrypt.hash(password, salt)
// step4 insert the info into the db
const newUser = await pool.query("INSERT INTO users (user_name, user_email, user_password)
VALUES ($1, $2, $3) RETURNING *", [name, email, bcryptPassword])
// step5 generate a jwt token
const token = jwtGenerator(newUser.rows[0].user_id, newUser.rows[0].user_name)
res.json( token )
catch (err)
console.error(err.message)
res.status(500).json("Server Error (register)")
)
// login and logout
router.post("/login", validInfo, async (req, res) =>
try
// step1 deconstruct req.body
const email, password = req.body
// step 2 check if user doesnt exist and if not throw and error
const user = await pool.query("SELECT * FROM users WHERE user_email=$1", [email])
if(user.rows.length === 0)
return res.status(401).json("User email is incorrect or does not exist.")
// step 3 check if incoming pword is the same as db password
const validPassword = await bcrypt.compare(password, user.rows[0].user_password)
if(!validPassword)
return res.status(401).json("Password is incorrect.")
// step4 give them a jwt token
const token = jwtGenerator(user.rows[0].user_id, user.rows[0].user_name)
res.json( token )
catch (err)
console.log(err.Message)
res.statusMessage(500).json("Server Error (login)")
)
router.get("/is-verified", authorization, (req, res) =>
try
res.json(true)
catch (error)
console.log(err.Message)
res.statusMessage(500).json("Server Error (is-verified)")
)
module.exports = router;
这里是dashboard.js 数据库和连接:
const router = require("express").Router()
const pool = require("../db")
const authorization = require("../middleware/authorization")
// all connections and name
router.get("/", authorization, async (req, res) =>
try
res.json(req.user.name)
if(req.user.name === 'lead')
const lead = await pool.query("SELECT * FROM connections LEFT JOIN
users ON users.user_id = connections.user_id")
... A bunch of sql queries here that work fine...
res.json(
admin: req.user.name,
results: lead.rows,
// aggregated queries
studentsEngaged: studentsEngaged.rows,
gender:gender.rows,
distinctStudents: distinctStudents.rows,
amountSep: amountSep.rows,
amountOct:amountOct.rows,
amountNov: amountNov.rows,
amountDec: amountDec.rows,
studentSessions:studentSessions.rows,
homeVisits: homeVisits.rows,
outsideAgencies: outsideAgencies.rows,
cpReferrals: cpReferrals.rows,
amountReferrals:amountReferrals.rows,
amountDischarges: amountDischarges.rows,
clas-s-roomPresentations: clas-s-roomPresentations.rows,
groupSessions: groupSessions.rows,
checkins: checkins.rows,
crisisInterventions: crisisInterventions.rows,
parentContacts: parentContacts.rows,
meetings : meetings.rows
)
else
const user = await pool.query("SELECT u.user_name, c.connection_id,
c.contact_type, c.contact_method, c.provision, c.connection_date,
c.student_id,
c.purpose, c.gender, c.yearGroup, c.school, c.referral_discharge,
c.cp_referral
FROM users AS u LEFT JOIN connections AS c ON u.user_id = c.user_id WHERE
u.user_id= $1", [req.user.id])
res.json(user.rows)
catch (err)
console.error(err.message)
res.status(500).json("Server Error (dashboard catch)")
)
// create connection
router.post("/connections", authorization, async (req, res) =>
try
// console.log(req.body);
const student_id, contact_type, yearGroup, school, contact_method,
gender, purpose, provision, connection_date, referral_discharge, cp_referral
=
req.body;
const newConnection = await pool.query(
"INSERT INTO connections (user_id, student_id, user_name, contact_type,
yearGroup, school, contact_method, gender, purpose, provision,
connection_date,
referral_discharge, cp_referral) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9,
$10, $11, $12, $13) RETURNING *",
[req.user.id, student_id, req.user.name, contact_type, yearGroup, school,
contact_method, gender, purpose, provision, connection_date,
referral_discharge,
cp_referral]
);
res.json(newConnection.rows[0]);
// console.log(newConnection.rows[0])
catch (err)
console.error(err.message)
);
// update connection
router.put("/connections/:id", authorization, async (req, res) =>
try
const id = req.params;
const student_id, contact_type, yearGroup, school, contact_method,
gender, purpose, provision, connection_date, referral_discharge, cp_referral
=
req.body;
const updateConneciton = await pool.query(
"UPDATE connections SET student_id=$1, contact_type=$2, yearGroup=$3,
school=$4, contact_method=$5, gender=$6, purpose=$7, provision=$8,
connection_date=$9, referral_discharge=$10, cp_referral=$11 WHERE
connection_id =
$12 AND user_id = $13 RETURNING *",
[student_id, contact_type, yearGroup, school, contact_method, gender,
purpose, provision, connection_date, referral_discharge, cp_referral, id,
req.user.id]
);
if (updateConneciton.rows.length === 0)
return res.json("This connection is not yours");
res.json("Connection was updated");
catch (err)
console.error(err.message);
);
// delete connection
router.delete("/connections/:id", authorization, async (req, res) =>
try
const id = req.params;
const deleteConnection = await pool.query(
"DELETE FROM connections WHERE connection_id = $1 AND user_id = $2
RETURNING *",
[id, req.user.id]
);
if (deleteConnection.rows.length === 0)
return res.json("This connection is not yours");
res.json("Connection was deleted");
catch (err)
console.error(err.message);
) ;
这是我的 App.js:
function App()
const [isAuthenticated, setIsAuthenticated] = useState(false)
const setAuth = (boolean) =>
setIsAuthenticated(boolean)
async function isAuth()
try
const response = await fetch("/auth/is-verified",
method:"GET",
headers:token: localStorage.getItem("token")
)
var parseRes = await response.json()
// if(parseRes === true || parseRes === undefined)
// setIsAuthenticated(true)
// else
// setIsAuthenticated(false)
//
////////this didn't work, just checking which would occur first, error or
this conditional
parseRes === true ? setIsAuthenticated(true): setIsAuthenticated(false)
catch (err)
console.error(`(App Catch)$err.message`)
useEffect(() =>
isAuth()
)
return (
<Fragment>
<Router>
<div>
<Switch>
<Route exact path="/" render=props => !isAuthenticated ? <Root
...props /> : <Redirect to='/dashboard'/> />
<Route exact path="/landing" render=props => !isAuthenticated ?
<Landing ...props /> : <Redirect to='/dashboard'/> />
<Route exact path="/register" render=props => !isAuthenticated ?
<Register ...props setAuth =setAuth /> : <Redirect to='/login'/> />
<Route exact path="/login" render=props => !isAuthenticated ? <Login
...props setAuth =setAuth auth=isAuthenticated/> : <Redirect
to='/dashboard'/> />
<Route exact path="/dashboard" render=props => isAuthenticated ?
<Dashboard ...props setAuth =setAuth /> : <Redirect to='/login'/> />
</Switch>
</div>
</Router>
</Fragment>
);
export default App;
enter code here
【问题讨论】:
您是否检查过您的令牌是如何从此文件(“../utils/jwtGenerator”)中签名的?令牌可能只在很短的时间内有效 是的,考虑到“jwt expired”我做了,但是如果我在一天后输入用于登录的 url,我有一个基于身份验证状态的三元运算符,可以适当地重定向到仪表板。我将在问题的底部包含我的 App.js。 【参考方案1】:在授权.js 中,代码被破坏,我消除了返回和状态消息并使用“res.redirect(“/”);”这会导致程序在每种情况下重定向 1. 令牌无效 2. 标头中没有提供令牌。重定向将用户带回登录页面,在该页面检查 localStorage,如果存在有效令牌,则将重定向到仪表板。最终,如果获得授权,我不会返回状态消息,而是重定向回仪表板。
【讨论】:
以上是关于尝试使用有效令牌直接访问页面时,JWT 身份验证不起作用;将在登录时开始工作。反应/节点/快递的主要内容,如果未能解决你的问题,请参考以下文章
Auth0 - 在 Owin 上使用带有承载访问令牌的 JWT 使用 RS256 进行身份验证
Laravel Tymon\JWT Auth:在身份验证之前检查未完成的有效令牌?
尝试访问我的 api 平台时未找到 JWT 令牌 401 错误?