Node.js 使用 express-jwt 解析 JWT

Node.js 上 Token 鉴权经常使用的是 passport,它能够自定义校验策略,但若是你是用 express 框架,又只是解析 JWT 这种简单需求,能够尝试下 express-jwt 这个中间件。git

关于 JWT

JWT 全称 JSON Web Token,是代替传统 session 认证的解决方案。其原理是服务端生成一个包含用户惟一标识的 JSON 对象,颁发给客户端。客户端请求须要权限的接口时,只要把这个 JSON 再原样发回给服务端,服务器经过解析就可识别用户。github

它一般是这个样子:web

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
复制代码

这个 JSON 对象经过 . 分红三段,包含了请求头(加密算法)、负载信息(如 userId、过时时间),还有经过服务端密钥生成的签名来保证不被篡改。算法

这种机制使服务端再也不须要存储 Token,所以是很是轻量的用户认证方案。而且对于微服务这种须要不一样服务间共用 Token 的跨域认证,JWT 是目前的首选。shell

关于 express-jwt

express-jwt 是 Node.js 的一个开源库,由 ID 认证服务提供商 auth0 开发,是专用于 express 框架下解析 JWT 的中间件。express

它使用很是简单,并且会自动把 JWT 的 payload 部分赋值于 req.user,方便逻辑部分调用。npm

开始使用

安装

npm install express-jwt
复制代码

加入中间件

const expressJwt = require('express-jwt')

app.use(expressJwt({
  secret: 'secret12345'  // 签名的密钥 或 PublicKey
}).unless({
  path: ['/login', '/signup']  // 指定路径不通过 Token 解析
}))
复制代码

生成 Token

生成 Token 的方式依然使用 jsonwebtoken,好比将下列代码加入到登陆接口的返回部分:编程

const jwt = require('jsonwebtoken')

app.post('/login', function (req, res) {
  // 注意默认状况 Token 必须以 Bearer+空格 开头
  const token = 'Bearer ' + jwt.sign(
    {
      _id: user._id,
      admin: user.role === 'admin'
    },
    'secret12345',
    {
      expiresIn: 3600 * 24 * 3
    }
  )
  res.json({
    status: 'ok',
    data: { token: token }
  })
})
复制代码

获取解析内容

当收到带 Token 的请求,若是解析成功,就能够在路由回调里经过 req.user 来访问:json

app.get('/protected', function (req, res) {
  if (!req.user.admin)
    return res.sendStatus(401)
  res.sendStatus(200)
})
复制代码

req.user 实际就是 JWT 的 payload 部分:跨域

{
  _id: '5dbbc7daaf7dfe003680ba39',
  admin: true,
  iat: 1572587484,
  exp: 1573192284
}
复制代码

解析失败

若是解析失败,会抛出 UnauthorizedError,能够经过后置中间件来捕获:

app.use(function (err, req, res, next) {
  if (err.name === 'UnauthorizedError') {   
    res.status(401).send('invalid token')
  }
})
复制代码

修改结果字段

默认解析结果会赋值在 req.user,也能够经过 requestProperty 来修改:

app.use(expressJwt({
  secret: 'secret12345',
  requestProperty: 'auth'
}))
复制代码

容许无 Token 请求

当接口容许不带 Token 和带 Token 两种状态的访问时(好比文章详情登陆后判断点赞),能够经过 credentialsRequired: false 来对无 Token 请求不进行解析和抛出异常。

app.use(expressJwt({
  secret: 'secret12345',
  credentialsRequired: false
}))
复制代码

自定义解析

默认状况下,express-jwt 是从请求 Headers 的 Authorization 字段来获取 Token 并解析。

经过 getToken 也能够自定义一些解析逻辑,好比使用其余 Header 字段,自定义抛出异常等:

app.use(expressJwt({
  secret: 'secret12345',
  credentialsRequired: false,
  getToken: function fromHeaderOrQuerystring (req) {
    if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
      return req.headers.authorization.split(' ')[1]
    } else if (req.query && req.query.token) {
      return req.query.token
    }
    return null
  }
}))
复制代码

吊销 Token

在 JWT 机制中,因为 Token 一般不进行存储,若是想吊销某一条 Token,通常都是经过被动的方式。

经常使用的方式是创建某个字段的黑名单(好比 TokenId),对全部 Token 进行过滤,express-jwt 专门提供了回调来处理这种状况:

const expressJwt = require('express-jwt')
const blacklist = require('./blacklist')

let isRevokedCallback = function(req, payload, done){
  let issuer = payload.iss
  let tokenId = payload.jti

  blacklist.getRevokedToken(issuer, tokenId, function(err, token){
    if (err) { return done(err) }
    return done(null, !!token)  // 第二个参数为 true 则不经过
  })
}

app.use(expressJwt({
  secret: 'secret12345',
  isRevoked: isRevokedCallback
}))
复制代码

更多用法能够查看 官方文档


本文属于原创内容,首发于微信公众号「面向人生编程」,如需转载请在公众号后台留言。

关注后回复如下信息获取更多资源 回复【资料】获取 Python / Java 等学习资源 回复【插件】获取爬虫经常使用的 Chrome 插件 回复【知乎】获取最新知乎模拟登陆
相关文章
相关标签/搜索