1 什么是JWT JWT是JSON WEB TOKEN的缩写,是为了在网络应用环境建传递声明而执行的一种基于JSON的开放标准。该Toekn被设计为紧凑并且安全的,特别适用于分布式站点的单点登录(SSO) ![]() 2 传统的session认证 传统的session认证是为了让我们的而英勇能识别是哪个用户发送的请求,需要在服务器存储一份用户的登陆信息,这份登陆信息会在返给用户的响应时传递给浏览器,浏览器保存为cookie,下次请求时发送给服务器,用来验证用户身份。 ![]() 基于session认证存在一些问题:
3 基于token的鉴权机制 基于token的鉴权机制类似于http协议,也是无状态的,不需要在服务端保留用户的认证信息或者会话信息。这就意味着基于token认证的应用不需要考虑用户在哪一台服务器登陆了,为应用的扩展提供了遍历。 ![]() 主要的流程如下:
4 JWT的构成 JWT由三段信息构成,第一部分为头部(header),第二部分为载荷(payload),第三部分是签名(signature) 4.1 header header用来描述描述关于该JWT的最基本的信息,承载两部分信息:
这也可以被表示成一个JSON对象。 { typ: JWT, alg: HS256}然后将头部进行base64加密,构成了第一部分 eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 4.2 payload 载荷是存放有效信息的地方,包含三个部分:
一个payload如下: { "sub": "1234567890", "name": "John Doe", "admin": true}然后对其进行base64编码,得到JWT的第二部分 eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9 4.3 signature 签名信息由三个部分组成:
secret是利用HS256T算法进行加密时的密钥,将header和payload使用secret进行加密后,构成了jwt的第三部分 // javascriptvar encodedString = base64UrlEncode(header) + . + base64UrlEncode(payload);var signature = HMACSHA256(encodedString, secret); // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ 将这三部分用.连接成一个完整的字符串,构成了最终的jwt 注意,jwt的签发生成是在服务器端的,secret是保存在服务端的,用来进行jwt的签发和验证。它是服务端的密钥,在任何场景都不应该流出。一旦客户端得到这个sercret,那就意味着客户端可以自我签发jwt了。 5 如何发送JWT 5.1 使用fetch发送 发送jwt时一般是在请求头里加入Authorization,并加上Bearer标注: fetch(api/user/1, { headers: { Authorization: Bearer + token }})服务端会验证token,如果验证通过就会返回相应的资源。 5.2 使用axios发送 在Vue中经常使用axios来帮助我们处理网络请求,使用axios设置请求头如下 import axios from axios;import JsonWebToken from jsonwebtoken;// 在登录成功后应该已经将token存到本机了const token = sessionStorage.getItem(userToken);// iss是我们预先定义信息,用来识别token是我们所需要的tokenconst isTokenValid = !!(token && JsonWebToken.decode(token) && (JsonWebToken.decode(token).iss === config.userToken.iss));// 如果token有效if (isTokenValid) { // get请求 axios.get(/api/user/deatil, { headers: { Authorization: Bearer + token, Cookie : sessionId= + sessionId + ; recId= + recId, } params: { param1: string, param2: string }, }) // post请求 axios.post(/api/user/deatil, { data: {value1: value} }, { headers: { Authorization: Bearer + token, Cookie : sessionId= + sessionId + ; recId= + recId, } }) // 全局设定 axios.headers.common[Authorization] = Bearer + token}6 在Koa2中的应用 jsonwebtoken是Node环境下JWT的实现,提供了一些API帮助我们快速的实现JWT的设计。 安装: $ npm install jsonwebtoken --save 6.1 签发token(加密) jwt.sign(payload, secretOrPrivateKey, [options, callback])
生成一个有效期为1小时的token: jwt.sign({ data: foobar}, secret, { expiresIn: 60 * 60 });jwt.sign({ data: foobar}, secret, { expiresIn: 1h });也可以用下面这种形式: jwt.sign({ exp: Math.floor(Date.now() / 1000) + (60 * 60), data: foobar}, secret);6.2 验证token 验证token的合法性: jwt.verify(token,secretOrPublicKey,[options,callback]) 来看验证时的一些简单的用法,更详细的用法参考官网。 // 同步验证成功var decoded = jwt.verify(token, shhhhh);console.log(decoded.foo) // bar// 异步验证成功jwt.verify(token, shhhhh, function(err, decoded) { console.log(decoded.foo) // bar});// 同步验证失败--token无效try { var decoded = jwt.verify(token, wrong-secret);} catch(err) { // err}// 异步验证失败--token无效jwt.verify(token, wrong-secret, function(err, decoded) { // err // decoded undefined})6.3 解码token的payload 将payload解码,注意:这个过程无论验证是否通过都会执行 jwt.decode(token [, options])// get the decoded payload ignoring signature, no secretOrPrivateKey neededvar decoded = jwt.decode(token);// get the decoded payload and headervar decoded = jwt.decode(token, {complete: true});console.log(decoded.header);console.log(decoded.payload)
看一下例子: // 解码payload不关心签名,不需要提供私钥var decoded = jwt.decode(token);// 获得对象var decoded = jwt.decode(token, {complete: true});console.log(decoded.header);console.log(decoded.payload)6.4 实际例子 来看一个实际的例子: const jwt = require(jsonwebtoken);//密钥,不能暴露const secret = aaa; // payload中不应该包含敏感信息const payload = { username: jay, userId: 123}// 选项(非必须)const options = { expiresIn: 60 * 60 * 24 // 或者为"1d"}// 生成tokenconst token = jwt.sign(payload, secret, options)// 验证tokenjwt.verify(token, secret, function (err, decoded) { // 如果验证通过 if (!err){ console.log(decoded.username); // jay }})7 kow-jwt 在Koa2中实现JWT的认证有中间件koa-jwt帮助我们完成,但是签发token的过程还是要安装上述过程,使用jsonwebtoken实现 直接看一个简单的例子: import Koa from koa;import jwt from koa-jwt;const app = new Koa();const router = new KoaRouter();const authRouter = auth.router;// 除了/public/之外的请求都需要经过JWT验证app.use(jwt({ secret: shared-secret }).unless({ path: [/^\/public/] }));// 无论请求中是否存在Authorization header都保证执行app.use(jwt({ secret: shared-secret, passthrough: true }));// 所有走/api/打头的请求都需要经过JWT验证router.use(/api, jwt({ secret: shared-secret }), apiRouter.routes()); 8 JWT的缺点和适用场景 这篇文章提出了一些自己观点,可以参考一下,它认为jwt的token方案最适合的场景是无状态的场景,若需要考虑token注销和某些token续签的场景,实际上就是给token加上了状态,这就类似于传统的方案了,但是相比传统方案的优势是,服务端可以不用长期保存用户状态,仅仅在一定时间段内保留一小部分状态即可。 9 总结 JWT的优点如下:
在安全方面需要注意:
Koa2中的具体实现:
#真想来了# |
| 本文出处: https://www.toutiao.com/a6573804310365209096/ |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|