使用节点将令牌保存在本地存储中

Posted

技术标签:

【中文标题】使用节点将令牌保存在本地存储中【英文标题】:Save Token in local Storage using node 【发布时间】:2016-01-19 15:59:11 【问题描述】:

我将 JWT ("jsonwebtoken": "^5.4.0") 与 express 4 和玉一起使用。 我能够创建正确的令牌,但是如何在每次调用中传递此令牌? 我必须在哪里存储这个令牌?在 headers 中还是在 localStorage 中?

现在我将 CURL 与 Postman 一起使用,并在标头中设置令牌

x-access-token

我是否创建了一个从数据库中检索令牌并在每次调用中使用它的中间件?

谢谢

【问题讨论】:

【参考方案1】:

您不需要从数据库中保存和检查令牌。这个令牌这样的机制可以只用你的服务器来解码,如果这样做了,那么令牌是有效的。你想做的代码应该是这样的。

var cookieParser = require('cookie-parser')
app.use(cookieParser())

app.get('/login', function(req, res, next) 
  var user = name:'test'; //!! find the user and check user from db then

    var token = jwt.sign(user, 'secret', 
            expiresInMinutes: 1440
          );

    res.cookie('auth',token);
    res.send('ok');

);

app.use(function(req, res, next) 

  var token = req.cookies.auth;

  // decode token
  if (token) 

    jwt.verify(token, 'secret', function(err, token_data) 
      if (err) 
         return res.status(403).send('Error');
       else 
        req.user_data = token_data;
        next();
      
    );

   else 
    return res.status(403).send('No token');
  
);

在这里你可以找到非常好的文章:https://scotch.io/tutorials/authenticate-a-node-js-api-with-json-web-tokens

【讨论】:

好的,但是如何为每个请求发送var token = req.body.token || req.query.token || req.headers['x-access-token']; ?如何使用节点和玉在标头中设置令牌? 是的,您应该发送的所有请求 如何使用 Jade 发送此令牌?此时我发送 With Curl 并使用 headers,但我想保存 Token 以自动发送。 对于 SPA 项目,使用标题。通过这种方法,我使用 cookie 这种方法的安全性如何?这样当我使用手机登录时,我会遇到什么问题吗?【参考方案2】:

如果您想要本地存储,我建议您检查一下:https://www.npmjs.com/package/node-localstorage

但是,话虽如此,你们不会相信我花了多长时间从上面的答案中找到res.cookie('auth' token)。我搜索了 Google 几个小时、Passport 文档、Express 文档、GraphQL 和身份验证/授权文档,试图找出如何以无状态方式将令牌获取到 API。

我已经构建了 JWT 令牌安全性并使用它来保护我的 GraphQL 解析器,但是后来我选择使用 EJS 和 graphql-request(与 Apollo 客户端大致相同),所以我需要找到一种方法将令牌传递给我的中间件不使用服务器端会话。

在 cookie 中存储 JWT 令牌很好,特别是如果您采取额外的预防措施(例如签署 cookie),我记得您还可以包含一些选项来保证 cookie 的安全,这样如果“浏览器" 允许访问 cookie。如果 cookie 使用您的服务器机密签名,则 cookie 中的数据根本无法更改并且仍然有效。风险总是有人泄露他们的令牌/cookie,如果这让您感到困扰,请研究刷新令牌。但是,API 令牌通常并且应该严格保密且安全。如果您将到期时间设置为 1 年,您最大的烦恼很可能是需要维护一份从现在起一年后到期的 JWT 的黑名单。

我只是在这里包含我的发现,因为这个问题实际上似乎是一种稀有资源......

这是我用于身份验证的 Express 中间件:

 // AUTHENTICATION
 app.use(async (req) => 
     try 
         const token = req.headers.authorization || req.cookies.auth
         const  person  = await jwt.verify(token, SECRET)
         req.person = person
         return req.next()
      catch (e) 
         return req.next()
     
 )
    您可以看到我正在将标头中的令牌设置为 cookie 作为后备。这很好地支持了我的需求,并允许我使用任何具有无状态安全性的客户端。 在我的视图和 GraphQL 解析器中,我的登录用户为 req.person。如果 req.person 未设置,则用户被视为未登录。 我正在使用return req.next(),这很重要,因为在没有参数的情况下调用next() 被视为“干净的转到下一个中​​间件和/或继续处理请求”。如果您包含任何字符串或对象参数,它会抛出一个错误,该错误会冒泡到您的错误处理中间件。你可以自己试试。将 return next('You are not authenticated.') 放在 catch 块中,您会看到它在您的路由之前停止请求。 我使用return next(),因为我在路由和解析器中处理授权。它提供了更大的灵活性,例如便于未经身份验证的用户访问注册和登录突变。

这是我的 GraphQL 端点(我正在使用 Apollo Server):

 app.use('/graphql', bodyParser.json(), graphqlExpress((req) => 
     const context = 
         person: req.person
     
     return 
         schema,
         context,
         rootValue: null
     
 ))
    在我的 GraphQL 解析器中,每个查询的第三个参数都有 context.person 填充有来自上述身份验证中间件的 req.person。 这就是一个人真正需要知道的一切。

下面是我如何使用名为graphql-request 的 NPM 包: https://www.npmjs.com/package/graphql-request

 app.get('/allpeople', async (req, res) => 
     try 
         const client = new GraphQLClient(GRAPHQL_ENDPOINT, 
             headers:  Authorization: req.headers.authorization || req.cookies.auth 
         )
         const query = `query allPeople($serialNumber: String!) 
             allPeople(serialNumber: $serialNumber) 
                 id
                 created
                 status
                 email
             
         `
         const variables = 
             serialNumber: req.person
         
         const response = await client.request(query, variables)
         res.render('allpeople/list',  people: response.allPeople )
      catch (e) 
         throw [`allPeople`, `$JSON.stringify(error, null, 2)`]
     
 )
    我包含此代码是因为没有“更高级”的 graphql-request 示例用法,到目前为止我很喜欢它。它非常简洁,如果您冒险使用 React.js,可以轻松地将其换成 Apollo Client。我这里的例子对于研究createNetworkInterfacenew ApolloClient() 的人来说也非常相关。

【讨论】:

以上是关于使用节点将令牌保存在本地存储中的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript本地存储详解

根据初始浏览器请求向服务器发送 JWT 令牌(使用本地存储)

在web api身份验证之后将令牌存储在浏览器本地存储中是否安全

如何保护 JWT 令牌

在浏览器关闭时为 React 明确清除本地存储

如何将 Token 保存到本地存储?