koa2,koa-jwt中token验证实战详解
用户身份验证通常有两种方式,一种是基于cookie的认证方式,另一种是基于token的认证方式。当前常见的无疑是基于token的认证方式。以下所提到的koa均为koa2版本。
token认证的优点是无状态机制,在此基础之上,可以实现天然的跨域和前后端分离等。
token认证的缺点是服务器每次都需要对其进行验证,会产生额外的运行压力。此外,无状态的api缺乏对用户流程或异常的控制,为了避免一些例如回放攻击的异常情况,大多会设置较短的过期时间。
准备工作
使用koa-jwt的大致流程是:
1. 用户通过身份验证API(登录)获取当前用户在有效期内的token
2. 需要身份验证的API则都需要携带此前认证过的token发送至服务端
3. koa会利用koa-jwt中间件的默认验证方式进行身份验证,中间件会进行验证成功和验证失败的分流。
koa-jwt中间件的验证方式有三种:
1. 在请求头中设置 authorization为Bearer + token,注意Bearer后有空格。(koa-jwt的默认验证方式)
{'authorization': "Bearer " + token}
2. 自定义getToken方法
3. 利用Cookie(此cookie非彼cookie)此处的Cookie只作为存储介质发给服务端的区域,校验并不依赖于服务端的session机制,服务端不会进行任何状态的保存。
实战逻辑:
1.在登录路由中进行验证,可携带用户名等必要信息,并将其放至上下文对象中。
router.post('/login', async (ctx, next) => {
const user = ctx.request.body;
if (user && user.username === 'tate') {
let {username} = user;
const token = sign({username, test: 'testok'}, secret, {expiresIn: '1h'});
ctx.body = {
mssage: 'GET TOKEN SUCCESS',
code: 1,
token
}
} else {
ctx.body = {
message: 'param error',
code: -1
}
}
})
2. 客户端登录成功并获取token信息后,将其保存在客户端中。如localstorage。
3. 在访问需要用户登录信息验证的接口是,需要将请求头设置authorization。此处我使用过两种方式:
(1)利用jquery或axios等前端库在对应的钩子中进行拦截设置请求头,此处以jq为例。这种思路有一个比较麻烦的点就是,所有需要验证的接口都需要单独设置请求头。如果用户自己通过url上拼装token进行访问,则不能实现对应效果。
$.ajax({
url: '/userinfo',
type: 'get',
data: {
param1: 'post1',
param2: 'post2',
token: localStorage.getItem('token')
},
beforeSend: function (xhr) {
xhr.setRequestHeader("authorization","Bearer " + localStorage.getItem('token'));
},
success: function (msg) {
console.log(msg);
},
fail: function (err) {
console.log(err);
}
})
(2)第二种就是利用koa的中间件在总路由中进行拦截处理。只要存在拼装了token字段的参数,就进行验证。此方法最大的优点就是遍历,但注意的一点是,需要在后端总路由拦截时做好架构,以免对其他路由造成干扰。
app.use(bodyParser())
app.use(async (ctx, next) => {
console.log(ctx)
let params =Object.assign({}, ctx.request.query, ctx.request.body);
ctx.request.header = {'authorization': "Bearer " + (params.token || '')}
await next();
})
3.利用koa-jwt设置需要验证才能访问的接口,验证成功后可在上下文中的state中获取状态信息。
router.get('/userinfo', jwt, async (ctx, next) => {
ctx.body = {username: ctx.state.user.username}
console.log(ctx)
})
.get('/viplist', jwt, async (ctx, next) => {
console.log(ctx.state)
ctx.body = 'check ok'
})
以下为核心后端文件的源码:
const koa = require('koa');
const app = new koa();
const bodyParser = require('koa-bodyparser');
const Router = require('koa-router');
const router = new Router();
const views = require('koa-views');
const static = require('koa-static');
const path = require('path');
const { sign } = require('jsonwebtoken');
const secret = 'demo';
const jwt = require('koa-jwt')({secret});
app.use(bodyParser())
app.use(views(__dirname + '/views', {
map: {html: 'ejs'}
}))
app.use(static(path.join(__dirname, '/static')))
app.use(async (ctx, next) => {
console.log(ctx)
let params =Object.assign({}, ctx.request.query, ctx.request.body);
ctx.request.header = {'authorization': "Bearer " + (params.token || '')}
await next();
})
router.get('/', async (ctx, next) => {
await ctx.render('index')
})
router.post('/login', async (ctx, next) => {
const user = ctx.request.body;
if (user && user.username === 'tate') {
let {username} = user;
const token = sign({username, test: 'testok'}, secret, {expiresIn: '1h'});
ctx.body = {
mssage: 'GET TOKEN SUCCESS',
code: 1,
token
}
} else {
ctx.body = {
message: 'param error',
code: -1
}
}
})
.get('/userinfo', jwt, async (ctx, next) => {
ctx.body = {username: ctx.state.user.username}
console.log(ctx)
})
.get('/viplist', jwt, async (ctx, next) => {
console.log(ctx.state)
ctx.body = 'check ok'
})
router.get('/404', async (ctx, next) => {
await ctx.render('404')
})
app
.use(router.routes())
.use(router.allowedMethods())
app.listen(3000, () => {
console.log('server is running at port 3000');
console.log(3)
})
koa2,koa-jwt中token验证实战详解的更多相关文章
- 011-Scala中的apply实战详解
011-Scala中的apply实战详解 object中的apply方法 class中的apply方法 使用方法 apply方法可以应用在类或者Object对象中 class类 必须要创建实例化的类对 ...
- Scala 深入浅出实战经典 第57讲:Scala中Dependency Injection实战详解
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- Scala 深入浅出实战经典 第55讲:Scala中Infix Type实战详解
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载: 百度云盘:http://pan.baidu.com/s/1c0noOt ...
- Scala 深入浅出实战经典 第54讲:Scala中复合类型实战详解
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- Scala 深入浅出实战经典 第53讲:Scala中结构类型实战详解
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...
- Scala 深入浅出实战经典 第58讲:Scala中Abstract Types实战详解
王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载: 百度云盘:http://pan.baidu.com/s/1c0noOt ...
- 第58讲:Scala中Abstract Types实战详解
这一讲我们来学习下抽像类型.让我们看下代码 package scala.learnimport scala.io.BufferedSourceimport scala.io.Source trait ...
- 第56讲:Scala中Self Types实战详解
今天学习了self type的内容,让我们来看下代码 package scala.learn class Self{ self => val tmp = "Scala" ...
- 第55讲:Scala中Infix Type实战详解
今天学习了Infix type的知识,来看看实战代码: def main(args:Array[String]){ object log { def >>:(data:String) ...
随机推荐
- spark教程(一)-集群搭建
spark 简介 建议先阅读我的博客 大数据基础架构 spark 一个通用的计算引擎,专门为大规模数据处理而设计,与 mapreduce 类似,不同的是,mapreduce 把中间结果 写入 hdfs ...
- react生态常用库分类
一. web项目 1.脚手架 create-react-app 自动安装react.react-dom 2.核心 react.react-dom 3.路由 react-router.react-rou ...
- 客户端相关知识学习(三)之Android原生与H5交互的实现
Android原生与H5交互的实现 H5调用原生的方式 方式可能有多种,根据开发经验,接触过两种方式. 方法一:Android向H5注入全局js对象,也就是H5调Android 1.首先对WebVie ...
- 109、Secret的使用场景 (Swarm16)
参考https://www.cnblogs.com/CloudMan6/p/8082429.html 我们可以用secret管理任何敏感数据.这些敏感数据是容器在运行时需要的.同时我们又不想把这些 ...
- webpack的基本使用
安装webpack npm i webpack -g npm i webpack-cli -g 1.基础用法(无需配置webpack.config.js文件) 1.2 新建需要打包的测试文件input ...
- 总结 | 慢 SQL 问题经验总结
1. 导致慢 SQL 的原因 在遇到慢 SQL 情况时,不能简单的把原因归结为 SQL 编写问题(虽然这是最常见的因素),实际上导致慢 SQL 有很多因素,甚至包括硬件和 mysql 本身的 bug. ...
- 关于redis的几件小事(一)redis的使用目的与问题
1.redis是用来干嘛的? Redis is an open source (BSD licensed), in-memory data structure store, used as a dat ...
- redis弱密码漏洞利用
背景: redis无认证,或者弱密码,可以成功连接到redis服务器 反弹shell拿到的权限取决于redis的启动账号 操作: 1. Centos7安装redis客户端 #yum install r ...
- ftp上传下载功能实现
该程序分为客户端和服务端,目前已经实现以下功能: 1. 多用户同时登陆 2. 用户登陆,加密认证 3. 上传/下载文件,保证文件一致性 4. 传输过程中现实进度条 5. 不同用户家目录不同,且只能访问 ...
- js判断网页标题包含某字符串则替换
js判断网页标题包含某字符串则替换,代码如下: var tit=document.title; if(tit.indexOf("afish")>0){ tit=tit.rep ...