上一篇主要和大家讲了session相关的内容,那这篇婧婧姐就跟大家聊聊token吧,主要从什么是 token,token的工作原理,NodeJS实现token以及token的优缺点去给大家讲解。
前言
1.Token的引入
以登录功能为例,传统的方式是在客户端频繁向服务端请求数据,服务端频繁的去数据库查询用户名和密码并进行对比,判断用户名和密码正确与否,并作出相应提示,此方式会造成服务器极大压力,在这样的背景下,token便应运而生。
2.Token的定义
token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成一个token,便将此token返回给客户端,以后客户端只需带上这个token前来请求数据即可,无需再次带上用户名和密码。
3.使用Token的目的
token的目的是为了减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮。
Token的工作原理
1.Token如何存储用户状态
基于token的身份验证是无状态的,我们不是将用户信息存储在服务器或者session中,而是直接把用户信息加密成token子串直接返回给客户端,客户端把token字段存储在客户端的本地存储(localStorage)即可。
2.Token的工作流程
1.客户端 向 服务端 发送登录HTTP请求,把用户名和密码发送给服务端。
2.服务端接收到客户端的登录请求,去数据库查询用户,登录验证成功,并返回一个签名的token给客户端。
3.客户端接收到服务端返回的token,把token存储在localStorage中,且用于每次发送的HTTP请求。
4.服务端接收到请求就会验证客户端携带过来的token,验证整个返回数据,否则返回未登录状态。
3.Token 的组成
token由三部分组成:
第一部分(header):声明加密算法。
第二部分(payload载荷):保存用户信息。
第三部分(signature签名):需要base64转码后的payload连接组成的字符串,然后通过header中声明的加密方式进行加密。
当然为了防止被人伪造篡改token,我们也可以随机加一段字符串秘钥进行混淆。
NodeJS实现Token
NodeJS生成token验证需要使用 jsonwebtoken 模块
1.安装
npm install jsonwebtoken --save
2.导入
// index.jsconst express=require("express");const jwt = require('jsonwebtoken');let app = express()// token的秘钥let secret = 'shfgeurij34y8u2p3'
3.登录成功,生成Token 令牌
app.post('/login',async (req, res) => { let { username, password } = req.body; let data = await db.query(`select * from user where username='${username}' and password='${password}';`); if (data.length == 0) { res.send({ code: 400, msg:'用户名或者秘密错误' }) return } let info = { ...data[0] } // 登录成功 生成token令牌 // jwt.sign() // 三个参数:参数1:payload 用户相关信息,参数2:秘钥,参数3:一个对象,过期时间,创建token的时间,或者token的id值 let token = jwt.sign(info, secret, { //Token有效时间 单位s // 单位可以是 '10h' '7 days' expiresIn: 60 * 60 * 10, }) res.send({ code: 200, msg: '登录成功', token })})
把生成的token令牌当成响应体返回给客户端,客户端把token令牌存储到localStorage中。
4.验证Token
每次发送请求都会把localStorage 中 token信息携带在请求头中的 authorization 传递给 后端。
后端数据中直接通过req.headers.authorizatio 来获取即可,然后使用jwt.verify() 来验证对应的token。
app.get('/getlist',(req, res) => { // 在req.headers.authorization 中获取传递过来的token let token = req.headers.authorization; // 使用jwt.verify()来验证token jwt.verify(token, secret, (error, decoded) => { // error 就是验证token错误的信息 if (error) { res.send({ code: 400, msg:'未登录' }) return } // decoded 解密之后的token res.send({ msg:'请求成功' }) })})
5.设置白名单统一验证Token
什么是白名单:即不需要做用户验证的接口。
一个网站中不是所有的数据接口都必须验证用户是否登录,很多数据接口为未登录的情况下也是可以正常请求,那么这一类型的数据接口 就可以设置为白名单。
比如:电商网站,商品列表就不需要登录也可以请求。
我们可以在所有的接口之前对session进行验证,也可以称之为session拦截。
// 登录接口不需要验证tokenlet white = ['/login','/register'];// 设置统一验证token// 就不需要每一个接口一个接口单独去验证server.use((req, res, next) => { // 获取req.url 来判断是否在白名单中 如果在白名单中 不需要验证token if (white.includes(req.url)) { next(); return } // 获取token来验证 let token = req.headers.authorization; jwt.verify(token, secret, (error, decoded) => { if (error) { res.send({ code: 400, msg:'未登录' }) return } //decoded.info 用户相关的信息 // 把 用户信息 存到req中,方便其他接口获取用户信息 req.info = decoded.info; next() })})// /user 不需要再验证,因为已经统一验证过了app.get("/user", (req, res) => { // req.info 获取从token验证出来的信息 res.send('返回正常的数据')});
Token的优缺点
优点
session身份验证也有自己的优缺点,那么token也不例外,那婧婧姐就先给大家聊聊token的优点吧。
-
防止CSRF 攻击:Session 验证是基于(cookie 中的 session_id)是由浏览器自动携带发送到服务端的,借助这个特性,攻击者就可以通过让用户误点攻击链接,达到攻击效果。而 token 是通过客户端本身逻辑作为动态参数加到请求中的,token 也不会轻易泄露出去,因此 token 在 CSRF 防御方面存在天然优势。
-
无状态、可扩展 :服务器只是生成token , 然后验证token,基于这种无状态和不存储Session信息,负载负载均衡器能够将用户信息从一个服务传到其他服务器上。
-
单点登录友好:使用 session 进行身份认证的话,实现单点登录,需要我们把用户的 session 信息保存在一台电脑上,并且还会遇到常见的 cookie 跨域的问题。但是,使用 token 进行认证的话, token 被保存在客户端,不会存在这些问题。.
-
项目应用更广泛:cookie不支持移动端,session需要依赖cookie,但是token不用。
缺点
接下来在来聊聊token的缺点。
-
占宽带:token加密字串,正常情况下要比session_id更大,需要消耗更多流量,挤占更多带宽。
-
无状态:token 的无状态,导致了它最大的缺点:当后端在token 有效期内用户Logout或者更改它的权限的话,不会立即生效,如果没有增加额外的处理逻辑,则一般需要等到有效期过后才可以。
结合上一篇的session,那么token和session的区别以及各自的优缺点和用法应该就一目了然了,每家公司使用的验证方式都不一样,最好的办法就是都会,赶紧学起来吧,毕竟技多不压身嘛!