node token node.js node
安装必要模块:
//koa-jwt 中间件,使用后为每个路由添加校验方法,就不需要一个个手动添加 npm install -S koa-jwt //生成token npm install -S jsonwebtoken@9.0.0 //对应node版本v12.20.2至少要》12
1,假设用户使用正确的帐号和密码登录,后台就会生成一个token,返回给浏览器,并保存在浏览器本地中,下次要进入后台就需要从本地获取到token传给后台
const jwt = require('jsonwebtoken'); //生成token router.get('/',async (ctx, next) => { //这里模拟,用户输入对的帐号密码时就会执行以下逻辑 const token = jwt.sign({ name: 123 },'user_pass_xxx' //随便一点内容,撒盐:加密的时候混淆 ,{ expiresIn: 60 //60秒到期时间 }); //把token存放在本地 ctx.cookies.set( 'state', token, { domain: 'localhost', // 写cookie所在的域名 path: '/', // 写cookie所在的路径 maxAge: 10 * 60 * 1000, // cookie有效时长 expires: new Date('2019-07-15'), // cookie失效时间 httpOnly: false, // 是否只用于http请求中获取 overwrite: false // 是否允许重写 } ) ctx.body='成功' })
生成的token内容类似于:(以下代码是JWT数据格式,具体可以参考地址)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxMjMsImlhdCI6MTQ5MTQ3NTQyNCwiZXhwIjoxNDkxNDc1NDg0fQ.hYNC4qFAyhZClmPaLixfN137d41R2CFk1xPlfLK10JU
//解密token jwt.verify(token, 'user_pass_xxx', function (err, decoded) { if (!err){ console.log(decoded.name); //会输出123,如果过了60秒,则有错误。 } })
2,把token用cookies存储在本地里,每次请求需要用帐号和密码校验对了才能显示的页面时,就必须把token从cookies里提取出来把token值带入到request headers,之后服务器才能获取到token值。
使用ajax把token值传入到request headers后在带给后台
3,服务器获取到客服端从request headers带入的token值后,就可以进行逻辑判断了,如果有token值并没过期就显示出相应的页面或数据
const app = new Koa() const koajwt = require('koa-jwt') app.use(async (ctx,next)=>{ //必须在koajwt验证之前把token传给服务器,不然根本访问不了路由 console.log('app.js里面'+ctx.cookies.get('state')); ctx.request.header = {'authorization': "Bearer " + ctx.cookies.get('state')} await next(); }); app.use(koajwt({secret: 'user_pass_xxx'}).unless({path:[/^\/api\/login/, /^\/api\/register/]})) //usless排除进行jwt校验的路由 //unless({ path: ['/public']}) ,每个路由都要校验token除了,访问/public路由时不需要 //在路由中处理 const router = require('koa-router')() router.post('/xxx', async ctx => { const token = ctx.state.user //从request headers带入token值,才能使用这种方法获取 console.log(token.id) console.log(token.secret) }
//单独为某个路由添加校验
get('/helloworld', koajwt({ secret: 'user_pass_xxx', // Should not be hardcoded }), async(ctx) => { ctx.body = 'helloworld page!' //通过了token才能显示内容 })
完成代码:
编辑app.js
const koajwt = require("koa-jwt"); // 自定义接口错误信息 app.use(async (ctx, next) => { return next().catch(err => { if (err.status === 401) { // 自定义返回结果 ctx.status = 200; console.log(err.name); ctx.body = { code: 401, msg: '登录超时'//err.message }; } else { throw err; } }); }); //以后每请求接口都会去拿cookie里面的token是否正常接口才能请求的通 app.use( koajwt({ secret:'user_pass_xxx', cookie: 'token', // 从 cookie 中获取token,cookie字段名是token debug: false // 开启debug可以看到准确的错误信息 }) .unless({ path:[/^\/login/, /^\/logout/, /^\/code_img/] }) ); // routes app.use(index.routes(), index.allowedMethods()) app.use(users.routes(), users.allowedMethods())
编辑路由的登录接口
const jwt = require('jsonwebtoken'); router.post('/login',async (ctx,next)=>{ var obj = await new Promise((a,b)=>{ db.get('username').find({"user":"admin"}).then((doc)=>{ var pass = en_pass((ctx.request.body.password)) if(doc[0].user===ctx.request.body.username && doc[0].pass===pass){ //客户端输入的账号密码和数据库匹配 //----------------生成token----------------------------------- const token = jwt.sign({ "username":ctx.request.body.username, "pass":pass },'user_pass_xxx' //随便一点内容,撒盐:加密的时候混淆 ,{ expiresIn: 60 * 60 * 24 //token24小时后过期 }); //----------------生成token----------------------------------- a(token); }else{ a(false); } }); }) ctx.body={ code:obj?200:401, data:obj?obj:null, msg:obj?'登录成功':'密码错误' } })
只要登录成功,就要让后端或者前端去生成cookie,且字段名为token值是jwt.sign()生成的,以后每请求接口都会效验token是否正常接口才能请求的通
参考文章有:
https://www.dengxiangxing.com/post/42072
https://www.jianshu.com/p/a7882080c541
https://segmentfault.com/a/1190000009494020
https://www.npmjs.com/package/jsonwebtoken