JWT是目前最流行的跨域认证解决方案
JWT的工作原理
当用户在客户端操作个人信息第一次提交账号和密码到服务端时,服务器端会验证账号和密码,验证通过后会将用户的信息对象进行加密,加密后生成Token字符串,此时服务器会将生成的Token字符串发送给客户端,把Token字符串存储在客户端的LocalStorage或SessionStorage中。
当客户端再一次与服务端通信发起请求时,都会携带这个Token字符串,并通过请求头的Authorization字段,将Token发送给客户端,在服务器会把Token字符串进行解密,还原成用户输入的信息对象,并进行用户的身份认证,认证成功后,服务器会对当前用户生成特定的响应内容,把当前用户对应的页面内容响应给浏览器。
Bearer Token(Token 令牌)
了解了JWT的工作原理后,我们要知道Bearer Token(Token 令牌)的概念:
为了验证使用者的身份,需要客户端向服务器端提供一个可靠的验证信息,称为Token,这个token通常由Json数据格式组成,通过hash散列算法生成一个字符串,所以称为Json Web Token(Json表示令牌的原始值是一个Json格式的数据,web表示是在互联网传播的,token表示令牌,简称JWT)
JWT的组成
JWT由三部分组成: Header
(头部)、Payload
(有效荷载)、Signature
(签名) 中间用点分隔
Payload
载荷部分是真正的用户信息,它是用户信息经过加密之后生成的字符串
标准中注册的声明(建议但不强制使用):
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token。
Header
和Signature
是安全性相关的部分,只是为了保证Token
的安全性
一段Token字符串如下:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNjAwODY0MjI4LCJleHAiOjE2MDA4NjQ4Mjh9.fcLkE5FH4u5fLVCvNXM4xFXxFj3JNaoLzpe7qdz8fug
在 express 中验证 JWT的认证机制
下面我们在erpress中测试JWT的认证机制:
在Node.js中测试,首先我们要安装两个加密和解密JWT相关的包:
jsonwebtoken
用于生成JWT
字符串express-jwt
用于将JWT
字符串解析还原成JSON
对象
TODO_01:安装并导入 JWT 相关的两个包,分别是 jsonwebtoken 和 express-jwt
const jwt = require('jsonwebtoken') //对用户数据进行jwt加密
const expressJWT = require('express-jwt') //解密
TODO_02:定义 secret 密钥,建议将密钥命名为 secretKey 密钥字符可以随便设置
var secretkey = 'dfhdsafdsgfhf' //密钥 提高安全性
TODO_03:在登录成功之后,调用 jwt.sign() 方法生成 JWT 字符串,并通过 token 属性发送给客户端
res.send({
status: 200,
message: '登录成功!',
token: 'Bearer' + jwt.sign({ username: userinfo.username }, secretkey, { expiresIn: '600s' })
})
TODO_04:注册将 JWT 字符串解析还原成 JSON 对象的中间件
app.use(expressJWT({ secret: secretkey, algorithms: ['HS256'] }).unless({ path: [/^\/api\//] }))
TODO_05:使用 req.user 获取用户信息,并使用 data 属性将用户信息发送给客户端
res.send({
status: 200,
message: '获取用户信息成功!',
data: req.user // 要发送给客户端的用户信息
})
TODO_06:使用全局错误处理中间件,捕获解析 JWT 过期失败后产生的错误
app.use((err, req, res, next) => {
//token解析失败导致的错误
if (err.name === 'UnauthorizedError') {
return res.send({ status: 401, message: '无效的token' })
}
//其他原因导致的错误
res.send({ status: 500, message: '未知错误' })
})
注意:secretkey是保存在服务器端的,jwt的签发生成也是在服务器端的,secretkey就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secretkey, 那就意味着客户端是可以自我签发jwt了。
postman中测试JWT结果