随着技术的发展,分布式web应用的普及,通过session管理用户登录状态成本越来越高,因此慢慢发展成为token的方式做登录身份校验,然后通过token去取redis中的缓存的用户信息。随着之后jwt的出现,校验方式更加简单便捷化,无需通过redis缓存,而是直接根据token取出保存的用户信息,以及对token可用性校验,单点登录更为简单

JSON Web Token由三部分组成,它们之间用圆点(.)连接,header.payload.signature

header存token类型和签名算法
payload存携带的数据,比如用户信息{id:1,name:‘txj’…},其中一些是: iss(发行人)、 exp(到期时间)、 sub(主题)、 aud(受众)
signature存签名,默认使用HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(payload), secret)

1、创建

$ npm install jsonwebtoken --save

jsonwebtoken用于创建和验证token

使用默认的HMAC SHA256生成

var jwt = require('jsonwebtoken');
var token = jwt.sign({ foo: 'bar' }, 'secret_shhhhh');

设置过期时间(1h过期)

// 方式一
jwt.sign({exp: Math.floor(Date.now() / 1000) + (60 * 60),data: 'foobar'
}, 'secret');// 方式二 推荐使用
jwt.sign({data: 'foobar'}, 'secret', { expiresIn: '1h' });
'1h’表示1小时过期
'7d’表示7天过期
数字1000表示1000毫秒过期

如果没有配置过期时间,则默认永不过期

eg:登录获取token

router.post('/token', async (ctx, next) => {let columnNames = ['admin_id','role_id','user_name','real_name','nick_name','portrait']let sql = `SELECT ${columnNames.join()} FROM admin WHERE user_name = ? AND password = ?`const md5Password = md5(password).toString()// 查不到数据时rows=[]const [rows,fields] = await mysqlPool.execute(sql, [userName,md5Password]);if(rows[0]){console.log('login success')// 创建tokenconst token = jwt.sign(rows[0], 'secret', { expiresIn: '2h' });ctx.body = {success: true, data: token}}else{// 账号或密码错误console.log('login failed')ctx.body = {success: false, message: '账号或密码错误'}}}); 

2、校验并解码

校验的同时会返回解码后的payload

// verify a token symmetric - synchronous
var decoded = jwt.verify(token, 'secret_shhhhh');
console.log(decoded) // { foo: 'bar', iat: 1644312929 }// 如果想要把3段都输出来,即{ header, payload, signature }
var decoded1 = jwt.verify(token, 'secret_shhhhh', {complete: true});
/* {header: { alg: 'HS256', typ: 'JWT' },payload: { foo: 'bar', iat: 1644312990 },signature: 'hTf9bM3S4Y9XaoRRr9LVWecDnPHZ7n4Ma9CrnmjRqSE'
}*/

如果解码失败

// invalid token - synchronous
try {var decoded = jwt.verify(token, 'wrong-secret');
} catch(err) {// err // 如果超时 err.message = 'jwt expired'// 如果token解析不了 err.message = 'invalid token'// 如果签名错误 err.message = 'invalid signature'// 其他错误查看GitHub// ctx.throw(401, 'token error');
}

github:https://github.com/auth0/node-jsonwebtoken

3、koa-jwt(jwt中间件、拦截器)

用于在所有请求的前置做token的校验,并自动解码token里的payload,然后放在ctx.state.user对象里。

当然也可以自己写个中间件,然后在中间件里使用jwt.verify来校验

npm install koa-jwt --save

GitHub:https://github.com/koajs/jwt

由于koa-jwt依赖了jsonwebtoken,所以安装了koa-jwt之后可以不用安装jsonwebtoken,可以直接var jwt = require(‘jsonwebtoken’);

eg:

var Koa = require('koa');
var jwt = require('koa-jwt');var app = new Koa();
// 自定义401错误 start 【可以不要,必须写在前面;洋葱模型,发生错误后是不会继续往下执行的】
// 如果token没有经过验证中间件会返回401错误,可以通过下面的中间件自定义处理这个错误
// Custom 401 handling if you don't want to expose koa-jwt errors to users
app.use(function(ctx, next){return next().catch((err) => {if (401 == err.status) {ctx.status = 401;ctx.body = 'Protected resource, use Authorization header to get access\n';// ctx.body = {error: err.originalError ? err.originalError.message : err.message};} else {throw err;}});
});
// 自定义401错误 end// Middleware below this line is only reached if JWT token is valid
// 登录注册接口不验证'/api/login','/api/register'
// 验证失败会返回401错误
app.use(jwt({ secret: 'my-secret' }).unless({ path: [/^\/api\/login/, /^\/api\/register/]}));// 不验证token的中间件 测试1
app.use(function(ctx, next){if (ctx.url.match(/^\/api\/login/)) {ctx.body = 'unprotected\n';} else {return next();}
});// 验证token的中间件 测试2
app.use(function(ctx){if (ctx.url.match(/^\/api/)) {ctx.body = 'protected\n';}
});app.listen(3000);

注意鉴权代码的位置,鉴权代码应该写在注册路由之前,写在koa-static(用了的话)等中间件之后,否则,请求静态资源路径也被鉴权。

如果不校验token,始终放行,配置passthrough: true

// 不校验token是否有效
app.use(jwt({ secret: 'my-secret', passthrough: true }));

如果secret有多个

app.use(jwt({ secret: ['old-my-secret', 'new-my-secret'] }));

4、怎么使用

a.前端发送请求时,token需要放在header里,格式为’Bearer[空格]token‘
Headers:{Authorization:'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.payload.sign'}

'Bearer’前缀是jwt标准要求的,参见:https://jwt.io/introduction/

b.后台直接使用ctx.state.user就可以获取payload里的值了,假设payload={name:‘txj’}
// koa-jwt中间件校验token成功才会执行下面的方法
router.get('/detail/:code', async (ctx, next) => {console.log('user:', ctx.state.user)  // {name:'txj',iat: 1644314969}
})

如果token校验失败,直接返回401至前台

c.如果不希望把值存在user属性里,比如想存在jwtdata里
app.use(jwt({ secret: 'secret_shhhhh',key: 'jwtdata' }).unless({ path: [/^\/api\/login/, /^\/api\/register/]}));

后面使用ctx.state.jwtdata取payload里的值

5、相对完整的版本

app.js

const Koa = require('koa');
const bodyParser = require('koa-bodyparser');
const router = require('./index.js')
const jwt = require('koa-jwt');const app = new Koa();// 用于cookie签名
app.keys = ['SHjUcKJS9TqcPWGk'];// logger
app.use(async (ctx, next) => {const start = new Date;await next();const ms = new Date - start;console.log(`${ctx.method} ${ctx.url} - ${ms}`);
});// 配置koa-bodyparser模块解析body
app.use(bodyParser());// 自定义401错误
// app.use(function(ctx, next){//   return next().catch((err) => {//     if (401 == err.status) {//       ctx.status = 401;
//       // ctx.body = 'Protected resource, use Authorization header to get access\n';
//       ctx.body = {error: err.originalError ? err.originalError.message : err.message};
//     } else {//       throw err;
//     }
//   });
// });// jwttoken鉴权
// 登录注册接口不验证'/api/login','/api/register'
// 验证失败会返回401错误
app.use(jwt({ secret: 'secret_shhhhh' }).unless({ path: [/^\/api\/login/, /^\/api\/register/]}));// 配置路由中间件
app.use(router.routes()).use(router.allowedMethods());;// 全局监听异常信息
app.on('error', err => {console.error('server error', err)
});app.listen(8910);
console.log('listening on port 8910');

index.js

const Router = require('@koa/router');
const imageTextRoutes = require('./imageText.js')
const indexService = require('../service/index.js')const router = new Router({prefix: '/api'
});// 指定一个url匹配
router.get('/indexData', async (ctx) => {// 这里可以直接获取token里的payloadconsole.log('cccc:', ctx.state.user)// let body = ctx.request.body;const data = await indexService.getIndexData({current: ctx.query.current,size: ctx.query.size})ctx.body = {success: true,data: data}})router.use('/article', imageTextRoutes.routes(), imageTextRoutes.allowedMethods());module.exports = router

koa2中使用jwt相关推荐

  1. mysqljs在koa2中的正确姿势

    截止到今天,mysqljs在github上已经获取到了10000+star了,可以说是实实在在最流行的mysql驱动了,但是要把mysqljs应用到koa2中,似乎不太方便,koa2使用最新的语法as ...

  2. 如何简单的在 ASP.NET Core 中集成 JWT 认证?

    前情提要:ASP.NET Core 使用 JWT 搭建分布式无状态身份验证系统 文章超长预警(1万字以上),不想看全部实现过程的同学可以直接跳转到末尾查看成果或者一键安装相关的 nuget 包 自上一 ...

  3. ASP.Net Core 3.1 中使用JWT认证

    JWT认证简单介绍 关于Jwt的介绍网上很多,此处不在赘述,我们主要看看jwt的结构. JWT主要由三部分组成,如下: HEADER.PAYLOAD.SIGNATURE HEADER包含token的元 ...

  4. ASP.NET Core WebAPI中使用JWT Bearer认证和授权

    为什么是 JWT Bearer ASP.NET Core 在 Microsoft.AspNetCore.Authentication 下实现了一系列认证, 包含 Cookie, JwtBearer,  ...

  5. aspnet core 2.1中使用jwt从原理到精通二

    在aspnet core中,自定义jwt管道验证 有了上一节的内容作为基础,那这点也是非常容易的,关键点在中间件,只是把上一级在测试类中的自定义验证放到中间件中来即可, 不过需要注意:中间件 的位置很 ...

  6. jwt token 过期刷新_如何在SpringBoot中集成JWT(JSON Web Token)鉴权

    这篇博客主要是简单介绍了一下什么是JWT,以及如何在Spring Boot项目中使用JWT(JSON Web Token). 1.关于JWT 1.1 什么是JWT 老生常谈的开头,我们要用这样一种工具 ...

  7. 在SPA应用中利用JWT进行身份验证

    版权声明:本文为博主chszs的原创文章,未经博主允许不得转载. https://blog.csdn.net/chszs/article/details/79639919 在SPA应用中利用JWT进行 ...

  8. koa2 mysql 事务_mysqljs在koa2中的正确姿势

    截止到今天,mysqljs在github上已经获取到了10000+star了,可以说是实实在在最流行的mysql驱动了,但是要把mysqljs应用到koa2中,似乎不太方便,koa2使用最新的语法as ...

  9. jwt php tp5,TP5框架中使用JWT的方法示例

    本文实例讲述了TP5框架中使用JWT的方法.共享给大家供大家参考,详细如下: 可以直接去github上下载,也可以使用composer 使用composer的话要保证你的电脑上安装了composer, ...

最新文章

  1. 石家庄地铁售票系统源码及截图(结对作业)
  2. 计算营业额python_用python教你计算定投能获得多少收益
  3. linux ntp 'ntp_request.c'远程拒绝服务漏洞,NTP拒绝服务漏洞(CVE-2015-5146)
  4. 2021年Z世代“潮力量”洞察报告
  5. 7-38 数列求和-加强版(20 分)
  6. php中对象是引用类型吗?
  7. Oracle设置主键自增
  8. 百度竞价每天如何优化
  9. 那些惊艳的算法—时间轮任务调度(sunwind整理)
  10. ChatGPT介绍以及一些使用案例
  11. 如何创建 2023 年营销日历(内含免费模板和示例)
  12. 《孙子兵法》十三篇原文——孙武
  13. 1077篇 ! ICCV2019论文接收结果公布(附70篇论文链接抢先读,含Oral) 更新中
  14. IPUtils工具类
  15. PostgreSQL 11 新特性之 PL/pgSQL 增强
  16. 全志V853开发板--构建编译
  17. 下一代网络:大道至“简”
  18. 如何在三个月内创立一家估值200亿的游戏公司?
  19. 如何在Tomcat中做TLS客户端认证
  20. bdf比特数字基金_PJBlog5 Installer

热门文章

  1. GO: go.mod go.sum
  2. 有趣的马氏链及其平稳分布
  3. js原型链(详细图解)
  4. phpmailer 通过smtp发送邮件,相同发送内容有的成功有的失败
  5. 在 Mac 和蓝牙设备间共享文件
  6. 在那江南烈日与阵雨中-江南100赛记
  7. 针对meshlab应用纹理出现错误的解决方法(You need to have at least one valid raster layer in your project)
  8. 用友软件系统管理员账号admin密码忘记了,如何解决?
  9. Python 上下文管理器和with块 一
  10. flutter dio 示例