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