看文章之前,强烈建议先把我的项目拉取下来!案例来自小弟的开源我的项目
「我的项目 Github」
文章内容只是集体学习的一些总结经验,不具备权威性,这是 Node 服务端的实现,前面会写前端的实现
什么是 Token 验证
常见的 Token 验证形式种:
OAuth2
,例如:微信受权登录 (貌似也属于 Token 验证)基于 JWT 的 Token 验证
,KiteBlog
外面应用的就是这种。
举荐浏览:
JWT 超详细分析
说一说几种罕用的登录认证形式,你用的哪种
什么是 JWT (JSON WEB TOKEN)?
举荐浏览:
JSON Web Token 入门教程
JSON Web Token – 在 Web 利用间平安地传递信息
NodeJS (Express) 中实现 Token 的生成和验证
装置 jsonwebtoken 和 express-jwt
首先咱们先装置 jsonwebtoken
和 express-jwt
这两个中间件
jsonwebtoken
: 用于生成 Token。它也有解析 Token 的性能
express-jwt
: 用于解析 Token(比 jsonwebtoken
解决不便), 它把解析之后的数据,寄存到 requset.user
中
# 装置 jsonwebtoken
npm i jsonwebtoken
# 装置 express-jwt
npm i express-jwt
复制代码
生成 token
如果你看了下面 JWT 介绍的文章,就晓得 JWT 是由三局部组成的,别离是 载荷 (Payload)
、 头部 (Header)
、 签名(Signature)
。
jsonwebtoken
给咱们提供了 sign(payload, secretOrPrivateKey, [options, callback])
办法。sign 办法对应的其实就是 JWT 签名 (Signature)
的动作
payload:荷载,参数类型:对象 secretOrPrivateKey:自定义的密钥,密钥属于敏感信息。参数类型:字符串 options:能够配置 header、荷载、指定算法类型。参数类型:对象 callback:回调
眼尖的敌人应该发现,payload
和 options
两个 参数
都能够配置荷,上面有例子。依据本人的习惯抉择就好
Payload 局部 JWT 规定了 7 个官网字段, 这些字段都是可选字段。可间接以对象的模式传给 payload
参数。
iss (issuer):签发人
exp (expiration time):过期工夫
sub (subject):主题
aud (audience):受众
nbf (Not Before):失效工夫
iat (Issued At):签发工夫
jti (JWT ID):编号
复制代码
options
中也能够承受以上七个字段,不过字段名称有所区别。
iss ---- issuer
exp ---- expiresIn
sub ---- subject
aud ---- audience
nbf ---- notBefore
iat ---- noTimestamp
jti ---- jwtid
复制代码
除此之后 options
提供了 algorithm
和header
,别离对应应用的加密算法和 JWT 的 Header 局部,其实 algorithm
应该也是属于 Header 局部的。
说了这么多,其实咱们个别罕用的只有 exp(expiresIn)
和 algorithm
这两个字段,
例子一:
token 的无效工夫是配置在 option
里
// 先引入 jsonwebtoken
var jsonWebToken = require('jsonwebtoken');
// 密钥,当然理论的我的项目中密钥应该变态一些
const SECRET_KEY = 'kite1874'
const token = jsonWebToken.sign({
// Payload 局部,官网提供七个字段这边省略,能够携带一些能够辨认用户的信息。例如 userId。// 千万不要是用敏感信息,例如明码,Payload 是能够解析进去的。userId:user.userId
role:user.role
},SECRET_KEY,{
expiresIn:"24h", //token 有效期
// expiresIn: 60 * 60 * 24 * 7, 两种写法
// algorithm:"HS256" 默认应用 "HS256" 算法
})
console.log(token)
复制代码
例子二:
咱们也能够在 payload
里配置无效工夫
const token = jsonWebToken.sign({
//exp 的值是一个工夫戳,这里示意 1h 后 token 生效
exp:Math.floor(Date.now() / 1000) + (60 * 60)
userId:user.userId
role:user.role
},SECRET_KEY)
复制代码
jsonwebtoken
除了生成 token 外,还提供了解析验证 token 的办法,jwt.verify(token, secretOrPublicKey, [options, callback])
。
这里就不演示了,感兴趣的敌人能够参考文档:「JsonWebToken」
验证 token
express-jwt
是针对 express
框架开发的 JWT Token
验证中间件。我先来简略说以下它的用法。
次要有两种形式,一种是哪些申请须要验证就往哪里加验证;另外一种是先给全副申请加上验证,再给不须要验证的申请配置 白名单
。
形式一:
var express = require('express');
var jwt = require('express-jwt');
var app = express();
//SECRET_KEY 要与生成 Token 时保持一致
const SECRET_KEY = 'kite1874'
// secret 为密钥,algorithms 为算法。须要留神的是,如果你生成 Token 的时候没有手动设置 algorithm
// 默认是应用 HS256 来加密的。「express-jwt 6.0」版本须要加 algorithms: ['HS256'] , 说起来都是泪!app.get("/test",
jwt({secret: SECRET_KEY, algorithms: ['HS256']}),
function(req,res){//do something...})
复制代码
看完下面的例子,很显然不合乎咱们的逾期,一个失常的我的项目有个几十个 api 是分分钟的事。咱们不可能一个个给他加上测验
形式二:
// 注册中间件,相当于配置一个全局 token 验证,unless 就是下面说的白名单
// 把不须要 token 验证的申请填进 path 里即可, 反对数组、字符串、正则
app.use(jwt({ secret: SECRET_KEY, algorithms: ['HS256']})
.unless({path: ['/auth/adminLogin',/^\/public\/.*/]}));
// /auth/adminLogin api 和 public 下的文件都不须要 token 验证
复制代码
这种形式是不是不便很多,而且更好看,保护起来也更不便
Token 解析进去的用户信息,默认寄存在 req.user
, 能够间接 req.user.userId
来应用生成 Token 时填进去的用户 id
你也通过 requestProperty
和 resultProperty
来设置用户信息寄存的对象。
这里就不开展,具体文档参考:express-jwt
验证错误处理
能够应用 app.use()
来注册解决验证不通过的状况
app.use(function (err, req, res, next) {if (err.name === 'UnauthorizedError') {res.status(401).send("干嘛呢?你想硬闯?!")
}
})
复制代码
留神(集体了解,不具备权威性)
到这里 Token 的生成、验证、测验不通过错误处理就实现了。Token 生成个别是在登录之后生成,并返回给前端,前端拿到 Token , 并在每次申请 api 的时候携带上 Token , Token 就相当于这个用户的身份,不要轻易泄露。
Token 一旦签发,不能被动让它生效,只能期待它有效期过能力生效。也就是说就算你批改了明码,之前的 Token 也还是无效的。你能够批改后端生成 Token 时应用的密钥,不让之前的 Token 测验通过,然而这就示意之前所有生成 Token 都生效了,做不到针对某个用户进行登记。这显然也不适合的。所以用户批改明码时,前端个别都要革除之前保留的 Token, 再重获取新的 Token
有敌人应该会想到在后端把 Token 储存起来,每一个用户对应一个 token。批改账号时,再生成一个新的 Token 笼罩之前的 Token,但这就违反了应用 Token 的目标,Token 的应用很大水平就为了缩小服务器的压力。把尽可能多的信息存储在客户端而不是服务端。
应用 Token 能够进攻 CSRF 攻打,之前写过一篇对于网络安全的文章,感兴趣的敌人能够看一下「XSS 攻打、CSRF 攻打、SQL 注入、流量劫持(DNS 劫持、HTTP 劫持)—— 浏览器平安」