重定向页面时如何将jwt存储在cookie中并将其传递给身份验证功能?

Posted

技术标签:

【中文标题】重定向页面时如何将jwt存储在cookie中并将其传递给身份验证功能?【英文标题】:How to store jwt in cookie and pass it to authentication function when redirecting a page? 【发布时间】:2019-10-24 17:29:14 【问题描述】:

我有一个使用 Postman 构建并使用 Jest 测试的 node.js express 后端。我用 hbs 写了一个前端,下一步是缝合它们。但是,我仍然不断收到来自我的身份验证函数的“请验证”错误消息,我猜这是因为我没有成功传递我的 jwt 令牌。

所以在登录页面(用户/登录)上,我想使用电子邮件和密码登录,然后我想重定向到我的页面(用户/我),在那里我可以执行属于该用户的其他操作。

前端 登录页面代码:

<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>

后端

在中间件/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) )

然后在网络/标题中,我有

请求网址:

http://localhost:3000/users/login

请求方法:

发布

状态码:

302 找到

远程地址:

推荐人政策:

降级时无推荐人

响应标头

连接:

保持活力

内容长度:

62

内容类型:

文本/html;字符集=utf-8

日期:

格林威治标准时间 2019 年 6 月 7 日星期五 18:41:47

地点:

/用户/我

设置 Cookie:

jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1Y2Y2NjNlMTQwMTQyYjE0MzhmZTJjNDMiLCJpYXQiOjE1NTk5MzI5MDd9.T_P8O-j98cs9gtahTzspJjx1qNMSe3M5OAySyeH2;最大年龄=3600;路径=/;过期=格林威治标准时间 2019 年 6 月 7 日星期五 19:41:47;仅http;安全

变化:

接受

X-Powered-By:

快递

没有请求 cookie,只有响应 cookie。我不确定这些是什么意思...@_@

我想通过 jwt 成功登录并正确呈现 me 页面,我该怎么做?

【问题讨论】:

JWT 应该有自己的验证过期时间。我不确定我们是否需要在顶部指定 cookie 过期时间。 document.cookie 不起作用,因为您的 cookie 是 httpOnly。 【参考方案1】:

您的 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。

【讨论】:

谢谢!我认为要解决这个问题我需要: 1. 使用 ngrok 创建一个安全隧道(我还没有学过); 2.修改本地文件以创建一个指向localhost的https主机,然后设置一个个人SSL证书。(我也不知道这个)我想也许暂时我应该切换回localStorage方法,直到后来我了解更多.【参考方案2】:

来自 express-session 文档:

只有在生产时才设置安全标签。

    if (app.get('env') === 'production') 
      app.set('trust proxy', 1) // trust first proxy
      sess.cookie.secure = true // serve secure cookies
    

【讨论】:

【参考方案3】:

首先:您无法在客户端查看 cookie,因为您设置了以下内容 ( secure:true, httpOnly:true) -secure 意味着它应该只在 https 网络上使用 cookie,而 -httpOnly 表示 cookie 应该被任何客户端 javascript 读取..

第二:你是真的在生成 jwt 后添加了“Authorization”标头,还是只是将它放在 cookie 中?

如果是,请尝试:

jwt.verify(token, <your secret>).then(user=> console.log(user)).catch(err=>console.log(err.toString());

对于以后可能遇到同样问题的人

【讨论】:

httpOnly 表示 cookie 不能被任何客户端 Javascript 读取【参考方案4】:

确保您已在服务器中安装cookie-parser

运行:

npm i cookie-parser

【讨论】:

以上是关于重定向页面时如何将jwt存储在cookie中并将其传递给身份验证功能?的主要内容,如果未能解决你的问题,请参考以下文章

如何存储 jwt 令牌以便重定向到其他子域不需要凭据

重定向后如何管理 JWT?

如何在没有 JWT idToken 的情况下管理 GITkit 账户?

如何使用标头中的用户 JWT 令牌转发授权并将其与 cookie 中的 JWT 令牌进行比较以验证用户?

OAuth提供者重定向后如何给用户JWT令牌?

如何在 CURL 重定向上传递 cookie?