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

标签 node.js express jwt graphql restful-authentication

我有一个 super 冗余的 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()
    }
})

在这个例子中,成功或失败都允许用户通过路由,但是 req.person 只有在用户登录时才会被填充。记住,这是一个异步的由于 async 关键字而产生的功能。它返回一个 promise ,我们正在使用 try/catch 架构。这允许我们使用 await 来暂停执行,直到 jwt.verify() 填充了 person。这使得 req.person 在每条 route 都可用。在此示例中,person 是您在执行 jwt.sign() 以创建 JWT 时指定的属性。这是一个可以唤起您内存的示例:

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 路由中,您可以简单地使第一行代码类似于:

// 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 模板引擎:

然后,所有路由之后,放置一个 splat 路由和一个错误处理中间件:

// 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
})

错误处理中间件需要放在最后,它有一个额外的第 4 个参数是 err,它包含 next() 的参数值,只有当您向它传递一个参数,即:next('Error happened')

上面的代码也可以在不对 GraphQL 进行任何更改的情况下使用。要在 GraphQL 中处理身份验证,只需检查一下:

// 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
    }
}))

GraphQL 端点必须安装在身份验证中间件之后。登录用户将在每个解析器中作为 context.person 可用,或者如果请求是非法的,context.person 将是假的。我会为以后搜索的任何其他人提及这一点。

关于node.js - 使用 Express JS 检查 API 请求授权的更好方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46615798/

相关文章:

mysql - 如何在 Node JS 上使用一对多关系表从 mysql 查询 js 创建 json 结果?

javascript - 无法通过子函数调用从数据库检索 Nodejs MySQl 数据

node.js - 将 Websocket 流量从 Nginx 代理到 Socket.io(无 SSL)

json - 如何使用expressjs通过body参数传递通用变量来更新属性

javascript - JWT 是如何做 Authentication 的

jwt - 将 koa-jwt 与 koa-router 一起使用

angularjs - HTML5 视频无法播放且媒体请求中止

javascript - 为 Node.js 捆绑 CommonJS 文件

javascript - 如何使用expressjs将数据从一个路由传递到另一个nodejs

express - 使用 Postman 在 header 中发送 JWT token