阅读 190

第四章 JWT 方案

什么是JWT?

  • JWT:即 JSON Web Tokens

  • 是一种跨域认证解决方案

JWT 解决了什么问题?

  • 数据传输简单高效

  • jwt 会生成签名,保证传输安全性

  • jwt 具有时效性

  • jwt 更高效利用集群做好单点登录

JWT 原理

  • 服务器认证后,生成一个JSON对象,后续通过JSON进行通信

JWT 数据结构

  • Header(头部)

  • Payload(负载)

  • Signature(签名)

image.png

Header结构

{     "alg": "HS256",     "typ": "JWT" } 复制代码

Payload结构 image.png

签名

image.png

JWT 使用方式

  • /api?token=xxx

  • cookie 写入 token

  • storage 写入 token,请求头添加:Authorization:Bearer <token>

通过 JWT 生成Token

文档地址:jsonwebtoken - npm (npmjs.com)

在后端项目安装

npm install jsonwebtoken 复制代码

/router/users.js中引入

const jwt = require('jsonwebtoken') 复制代码

使用,生成token,并随接口返回

// imooc 是密钥 let data = 用户信息对象; let token = jwt.sign({   data, }, 'imooc', { expiresIn: 30 }) 复制代码

请求携带Token

我们在登录的时候,将用户信息存储到了 localStorage中了,其中包含用户的token信息

所以在请求拦截的时候,在headers.Authorization中携带上token

这里应该还需要添加判断是否携带token,因为有的接口是不需要token的,目前我们先每次请求都携带上token

// 请求拦截 service.interceptors.request.use((config) => {    const headers = config.headers;    let token = storage.getItem('userInfo') ? storage.getItem('userInfo').token : ''    if (!headers.Authorization) {       headers.Authorization = 'Bearer ' + token    }    return config; }); 复制代码

接口验证Token

const router = require('koa-router')() const jwt = require('jsonwebtoken'); router.get('/count', (ctx)=>{     try {         // 获取请求中携带的Token         let authorization = ctx.request.header.authorization;         let token = authorization.split('Bearer ')[1];         // 验证Token,验证通过继续执行,验证不通过则走 catch         let payload = jwt.verify(token, 'imooc');                  ctx.body = 'token验证通过'     } catch(e) {         ctx.body = 'token验证未通过'     } }) 复制代码

关于返回值和密钥的说明:

/** * 因为生成token的时候,传的是是用户信息,密钥使用的是imooc */ let data = 用户信息对象; let token = jwt.sign({   data, }, 'imooc', { expiresIn: 30 }) /** * 所以验证token的时候,返回值就是我们前边生成的时候传的用户信息对象,使用的密钥也是imocc */ let payload = jwt.verify(token, 'imooc'); // payload 打印出来如下: > data: {deptId: [], state: 1, role: 1, roleList: [], createTime: "2021-10-09T07:47:36.566Z",…} > exp: 1633765828 > iat: 1633765798 复制代码

Token拦截

这里我们需要引入一个中间件的概念,在app.js中有好多中间件的使用;

如下

/** * ctx 上下文对象,同接口中的ctx * next() 继续执行 */ app.use(async (ctx, next) => {   await next() }) 复制代码

koa-jwt 中间件

文档地址:koa-jwt - npm (npmjs.com)

安装

npm i koa-jwt -S 复制代码

使用

const Koa = require('koa') const app = new Koa() const koaJwt = require('koa-jwt') const utils = require('./utils/utils') app.use(async (ctx, next) => {   return next().catch((err)=>{     if(err.status == 401) {       ctx.status = 200;       ctx.body = utils.fail('Token 认证失败', utils.CODE.AUTH_ERROR)     } else {       throw err;     }   }) }) // 要放在后边,secret的值是密钥 app.use(koaJwt({secret: 'imooc'})) 复制代码

判断是否验证Token

因为有些接口是不需要验证token的,比如说登录接口,这时候我们就使用koa-jwtunless方法,规定不需要验证token的接口;

// 比如不需要验证 /users/login app.use(koaJwt({secret: 'imooc'}).unless({      path: [/^/users/login/] })) // 需要注意的是,前端请求的是 /api/users/login,因为要配置跨域,所以加上了/api // 但是后端接收到的请求是没有 /api,所以要注意下不要把/api也写上 复制代码

从数据库中,查询指定的字段

因为我们不会将数据库中查询出来的所有字段,都返回给客户端

比如,查询用户信息的时候,一些像密码这种比较敏感的信息是不会返回的

这里就用到了一个mongo的语法

// 查询条件 let query = {   userName,   userPassword } // 需要查询出来的字段,是个字符串-多个字段用空格分开 let keys = 'userId userName userEmail' // User.findOne(查询条件, 字段) let res = await User.findOne(query, keys) 复制代码

findOne() 返回规定的字段,有三种写法

  1. 第一种就是上边的字符串形式,多个字段之间使用空格了连接

let keys = 'userId userName userEmail' let res = await User.findOne(query, keys) 复制代码

  1. 传入一个对象,1返回,0不返回;(0和1,只能写单独的一个,不能有的字段是0,有的是1,会报错)

let keys = {   userName: 1,   userId: 1 } let res = await User.findOne(query, keys) 复制代码

  1. 通过select()方法指定,值和方式一相同

let keys = 'userId userName userEmail' let res = await User.findOne(query).select(keys)


作者:日常push覆盖同事代码
链接:https://juejin.cn/post/7017707895227695140


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐