如何将 jwt 存储在 cookie 中并在重定向页面时将其传递给身份验证功能?
How to store jwt in cookie and pass it to authentication function when redirecting a page?
我有一个用 Postman 构建并用 Jest 测试的 node.js express 后端。我用hbs写了一个前端,接下来就是拼接了。但是,我仍然不断收到来自我的身份验证函数的 "please authenticate" 错误消息,我猜这是因为我没有成功传递我的 jwt 令牌。
所以在登录页面 (users/login) 我想用电子邮件和密码登录然后我想重定向到我的页面 (users/me) 在那里我可以执行属于这个用户的其他事情.
Front-end
登录页面代码:
<section class="login-bg">
<div class="login-form">
<p>Welcome to Task Manager, please log in!</p>
<form class="input-group" action="/users/login" method="POST">
<label>Email:</label>
<input type="email" name="email" placeholder="type your email" value="{{user.email}}" required >
<label>Password:</label>
<input type="password" name="password" placeholder="type your password" value="{{user.password}}" required>
<button class="button" type="submit">Log In</button>
</form>
</div>
</section>
Back-end
在middleware/auth.js
const jwt = require('jsonwebtoken')
const User = require('../models/user')
const auth = async (req, res, next) => {
try {
const token = req.header('Authorization').replace('Bearer ', '')
const decoded = jwt.verify(token, process.env.JWT_SECRET)
const user = await User.findOne({_id: decoded._id, 'tokens.token': token})
if (!user) {
throw new Error()
}
req.token = token
req.user = user
next()
} catch (error) {
res.status(401).send({error: 'Please authenticate.'})
}
}
module.exports = auth
在src/routers/users.js
router.post('/login', async (req, res) => {
try {
const user = await User.findByCredentials(req.body.email, req.body.password)
const token = await user.generateAuthToken()
res.cookie('jwt',token, { httpOnly: true, secure: true, maxAge: 3600000 })
res.redirect('/users/me')
} catch (error) {
res.status(400).send()
}
})
但是,当我在 users/me 中执行 console.log(document.cookie) 时,它说未定义。
然后我安装了 cookie-parser 并导入到 app.js,并尝试在 src/routers/users.js 中编写这部分:
router.get('/me', auth, async (req, res) => {
console.log('Cookies: ', req.cookies)
try {
res.render('me', {name: user.name})
} catch (error) {
res.status(500).send()
}
})
但是这个控制台不打印任何东西,可能是因为我从 auth 收到错误。
我的页面也附了一个js文件,但我不知道我是否可以这样写,可能是错误的:
const userToken = document.cookie.jwt.token
fetch('/users/me', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + userToken
}
})
.then(res => res.json())
.then(data => { console.log(data) })
.catch(err => { console.log(err) })
然后在网络中/Headers,我有
请求URL:
http://localhost:3000/users/login
请求方式:
POST
状态码:
302 个找到
远程地址:
推荐人政策:
no-referrer-when-downgrade
回应Headers
连接:
keep-alive
Content-Length:
62
Content-Type:
text/html;字符集=utf-8
日期:
2019 年 6 月 7 日星期五18:41:47格林威治标准时间
地点:
/users/me
Set-Cookie:
jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1Y2Y2NjNlMTQwMTQyYjE0MzhmZTJjNDMiLCJpYXQiOjE1NTk5MzI5MDd9.T_P8O-j98cs9gtahTzspJjx1qNMSe3M5OAySyeH25fs; Max-Age=3600;路径=/;到期=2019 年 6 月 7 日,星期五 19:41:47 GMT;仅限HTTP;安全
变化:
接受
X-Powered-By:
快递
没有请求 cookie,只有响应 cookie。我不确定这些是什么意思...@_@
我想通过 jwt 成功登录并正确呈现我的页面,我该怎么做?
您的 jwt 令牌 cookie 不起作用,因为它在以下代码中声明了标志 secure: true
:
res.cookie('jwt',token, { httpOnly: true, secure: true, maxAge: 3600000 })
这导致 HTTP 响应中出现 Secure
标志,表示此 cookie 仅在 HTTPS 环境下可用:
Set-Cookie:
jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1Y2Y2NjNlMTQwMTQyYjE0MzhmZTJjNDMiLCJpYXQiOjE1NTk5MzI5MDd9.T_P8O-j98cs9gtahTzspJjx1qNMSe3M5OAySyeH25fs;
Max-Age=3600; Path=/;
Expires=Fri, 07 Jun 2019 19:41:47 GMT; HttpOnly; Secure
由于您的请求 URL 使用 HTTP (http://localhost:3000/users/login
),浏览器将忽略该 cookie。
来自 express-session 文档:
仅在生产环境中设置安全标签。
if (app.get('env') === 'production') {
app.set('trust proxy', 1) // trust first proxy
sess.cookie.secure = true // serve secure cookies
}
首先:您无法在客户端查看cookie,因为您设置了以下内容({ secure:true, httpOnly:true})
-secure 意味着它应该只在 https 网络上使用 cookie,而
-httpOnly 表示 cookie 应该被任何客户端读取 Javascript..
其次:你真的在生成 jwt 后添加了“授权”header 还是你只是把它放在 cookie 中
如果是,则尝试:
jwt.verify(token, <your secret>).then(user=> console.log(user)).catch(err=>console.log(err.toString());
对于那些将来可能 运行 遇到同样问题的人
确保您已在服务器中安装 cookie-parser
。
运行:
npm i cookie-parser
在您的 app.js
文件中,添加:
const cookieParser = require('cookie-parser')
app.use(cookieParser())
它会起作用。
我有一个用 Postman 构建并用 Jest 测试的 node.js express 后端。我用hbs写了一个前端,接下来就是拼接了。但是,我仍然不断收到来自我的身份验证函数的 "please authenticate" 错误消息,我猜这是因为我没有成功传递我的 jwt 令牌。
所以在登录页面 (users/login) 我想用电子邮件和密码登录然后我想重定向到我的页面 (users/me) 在那里我可以执行属于这个用户的其他事情.
Front-end 登录页面代码:
<section class="login-bg">
<div class="login-form">
<p>Welcome to Task Manager, please log in!</p>
<form class="input-group" action="/users/login" method="POST">
<label>Email:</label>
<input type="email" name="email" placeholder="type your email" value="{{user.email}}" required >
<label>Password:</label>
<input type="password" name="password" placeholder="type your password" value="{{user.password}}" required>
<button class="button" type="submit">Log In</button>
</form>
</div>
</section>
Back-end
在middleware/auth.js
const jwt = require('jsonwebtoken')
const User = require('../models/user')
const auth = async (req, res, next) => {
try {
const token = req.header('Authorization').replace('Bearer ', '')
const decoded = jwt.verify(token, process.env.JWT_SECRET)
const user = await User.findOne({_id: decoded._id, 'tokens.token': token})
if (!user) {
throw new Error()
}
req.token = token
req.user = user
next()
} catch (error) {
res.status(401).send({error: 'Please authenticate.'})
}
}
module.exports = auth
在src/routers/users.js
router.post('/login', async (req, res) => {
try {
const user = await User.findByCredentials(req.body.email, req.body.password)
const token = await user.generateAuthToken()
res.cookie('jwt',token, { httpOnly: true, secure: true, maxAge: 3600000 })
res.redirect('/users/me')
} catch (error) {
res.status(400).send()
}
})
但是,当我在 users/me 中执行 console.log(document.cookie) 时,它说未定义。
然后我安装了 cookie-parser 并导入到 app.js,并尝试在 src/routers/users.js 中编写这部分:
router.get('/me', auth, async (req, res) => {
console.log('Cookies: ', req.cookies)
try {
res.render('me', {name: user.name})
} catch (error) {
res.status(500).send()
}
})
但是这个控制台不打印任何东西,可能是因为我从 auth 收到错误。
我的页面也附了一个js文件,但我不知道我是否可以这样写,可能是错误的:
const userToken = document.cookie.jwt.token
fetch('/users/me', {
method: 'POST',
headers: {
'Authorization': 'Bearer ' + userToken
}
})
.then(res => res.json())
.then(data => { console.log(data) })
.catch(err => { console.log(err) })
然后在网络中/Headers,我有
请求URL:
http://localhost:3000/users/login
请求方式:
POST
状态码:
302 个找到
远程地址:
推荐人政策:
no-referrer-when-downgrade
回应Headers
连接:
keep-alive
Content-Length:
62
Content-Type:
text/html;字符集=utf-8
日期:
2019 年 6 月 7 日星期五18:41:47格林威治标准时间
地点:
/users/me
Set-Cookie:
jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1Y2Y2NjNlMTQwMTQyYjE0MzhmZTJjNDMiLCJpYXQiOjE1NTk5MzI5MDd9.T_P8O-j98cs9gtahTzspJjx1qNMSe3M5OAySyeH25fs; Max-Age=3600;路径=/;到期=2019 年 6 月 7 日,星期五 19:41:47 GMT;仅限HTTP;安全
变化:
接受
X-Powered-By:
快递
没有请求 cookie,只有响应 cookie。我不确定这些是什么意思...@_@
我想通过 jwt 成功登录并正确呈现我的页面,我该怎么做?
您的 jwt 令牌 cookie 不起作用,因为它在以下代码中声明了标志 secure: true
:
res.cookie('jwt',token, { httpOnly: true, secure: true, maxAge: 3600000 })
这导致 HTTP 响应中出现 Secure
标志,表示此 cookie 仅在 HTTPS 环境下可用:
Set-Cookie:
jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1Y2Y2NjNlMTQwMTQyYjE0MzhmZTJjNDMiLCJpYXQiOjE1NTk5MzI5MDd9.T_P8O-j98cs9gtahTzspJjx1qNMSe3M5OAySyeH25fs;
Max-Age=3600; Path=/;
Expires=Fri, 07 Jun 2019 19:41:47 GMT; HttpOnly; Secure
由于您的请求 URL 使用 HTTP (http://localhost:3000/users/login
),浏览器将忽略该 cookie。
来自 express-session 文档:
仅在生产环境中设置安全标签。
if (app.get('env') === 'production') {
app.set('trust proxy', 1) // trust first proxy
sess.cookie.secure = true // serve secure cookies
}
首先:您无法在客户端查看cookie,因为您设置了以下内容({ secure:true, httpOnly:true}) -secure 意味着它应该只在 https 网络上使用 cookie,而 -httpOnly 表示 cookie 应该被任何客户端读取 Javascript..
其次:你真的在生成 jwt 后添加了“授权”header 还是你只是把它放在 cookie 中
如果是,则尝试:
jwt.verify(token, <your secret>).then(user=> console.log(user)).catch(err=>console.log(err.toString());
对于那些将来可能 运行 遇到同样问题的人
确保您已在服务器中安装 cookie-parser
。
运行:
npm i cookie-parser
在您的 app.js
文件中,添加:
const cookieParser = require('cookie-parser')
app.use(cookieParser())
它会起作用。