使用Express JS检查API请求授权的更好方法

我有一个超级冗余的server.js文件,因为几乎所有属于REST API的方法都是这样开始的,因为我必须在API请求中检查客户端是否有权要求特定的事情。

var jwt = require('jsonwebtoken'); // ... app.get('/getsomething', function(req, res) { "use strict"; var token = req.headers[tokenName]; if (token) { jwt.verify(token, app.get('some_secret'), { ignoreExpiration: false }, function(err, decoded) { if (err || typeof decoded === "undefined") { res.json({ status: 401, message: "unauthorized" }); } else { // actual code starts here... 

什么是更好的方法?

你应该有一个中间件来检查每一个进来的请求,例如:

 // AUTHENTICATION app.use(async (req) => { try { const token = req.headers.authorization const { person } = await jwt.verify(token, SECRET) req.person = person return req.next() } catch (e) { return req.next() } }) 

在这个例子中,成功或失败都允许用户通过路由,但是只有当用户login时才会填充req.person 。请记住,由于async关键字,这是一个asynchronous函数。 它返回一个承诺,我们正在使用try / catch架构。 这使我们可以使用await来停止执行,直到jwt.verify()已经填充完成为止。 这样就可以使req.person在每个路由中都可用。 在本例中, person是您在创buildJWT时执行jwt.sign()时指定的属性。 这里是一个例子来慢跑你的记忆:

 jwt.sign({ person: 'some unique identifier' }, 'secret', { expiresIn: '1y' }) 

这样, req.person只能通过解码有效的JWT来填充。 不要被const { person } = await jwt.verify(token, SECRET)所迷惑。 这和写作一样:

 const decodedJWT = await jwt.verify(token, SECRET) const person = decodedJWT.person 

在每一个受保护的路线中,您都可以简单地使第一行代码如下所示:

 // PROTECTED app.get('/radical', async (req, res, next) => { try { // If req.person is falsy, the user is not logged in if (!req.person) return res.status(403).render('error/403') // Otherwise, the user is logged in, allow him/her to continue // Replace res.render() with res.json() in your case. return res.render('radical/template', { person: req.person }) } catch (e) { return next(e) } }) 

此示例演示了EJS View模板引擎:

  • 请参阅: https : //www.npmjs.com/package/ejs

然后, 你所有的路线之后,放上一个图示路线和一个error handling中间件:

 // SPLAT ROUTE app.get('*', (req, res, next) => { return res.status(404).render('error/404') }) // ERRORS app.use((err, req, res, next) => { res.status(500).render('error/500') throw err }) 

error handling中间件需要最后一个,它有一个额外的第四个参数是err ,只有当你传递一个参数,即next('Error happened') ,它才包含next()参数的值。

上面的代码对GraphQL没有任何改变。 要在GraphQL中处理authentication,只需检查一下:

 // GRAPHQL app.use('/graphql', bodyParser.json(), graphqlExpress((req) => { const context = { person: req.person } return { schema, context, rootValue: null, formatError: (error) => ({ message: error.message, locations: error.locations, stack: error.stack, path: error.path }), debug: true } })) 

必须在authentication中间件之后安装GraphQL端点。 login的用户将作为context.person在每个parsing器中可用,或者如果请求是非法的,context.person将是虚假的。 我提到这是为了将来寻找其他人。