基于上节课讲的一些必要依赖之外,咱们须要安装一下依赖:html
咱们依次建立,并实现基础功能web
若有忘记,请参阅 Koa从零搭建到Api实现—项目的搭建
通常在涉及到密码等敏感信息存储数据库时,不可能明文存储,必须对其进行加密。而咱们最常使用的为md5加密
简单的密码md5加密后能够破解,可是稍微复杂一点的不可破解。故仍是很安全的算法
使用很简单数据库
const md5 = require('md5') md5(password)
一般咱们在用户注册时,获取用户录入的密码,加密后存到数据库。而在登陆时,先对密码加密,而后再与数据库中加密后的数据进行匹配。json
{ “typ”: “JWT”, “alg”: “HS256” }
由上可知,该token使用HS256加密算法,将头部使用Base64编码可获得一串字符串安全
eyJhbGciOiJIUzI1NiJ91服务器
{ “iss”: “Online JWT Builder”, “iat”: 1416797419, “exp”: 1448333419, ……. “userid”:10001 }
有效载荷中存放了token的签发者(iss)、签发时间(iat)、过时时间(exp)等以及一些咱们须要写进token中的信息。有效载荷也使用Base64编码获得一串字符串app
eyJ1c2VyaWQiOjB91async
将Header和Playload拼接生成一个字符串str=“eyJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOjB9”,使用HS256算法和咱们提供的密钥(secret,服务器本身提供的一个字符串)对str进行加密生成最终的JWT,即咱们须要的令牌(token),形如:str.”签名字符串”。ui
由上文所知,token是咱们根据Base64编码生成的,反之咱们对其进行解析,解析失败即token不合法
const md5 = require('md5') const jwt = require('jsonwebtoken') const secret = require('../config/secret.json') const login = async (obj) => { try { if (!obj.name || !obj.password) { return { err: '帐号和密码不能为空', success: false } } else { const name = await db.user.findAll({where: {name: obj.name}}) // 密码加密 obj.password = md5(obj.password) // 判断用户是否存在 if (name.length <= 0) { return {success: false, err: '当前用户不存在'} } else { let results = await db.user.findOne({where: obj}) // 验证用户密码 if (results) { // 写入token的信息 const userToken = { name: results.name, id: results.id } // 签发Token 1小时后过时 const token = jwt.sign(userToken, secret.sign, {expiresIn: '1h'}) return { success: true, token: token, data: results } } else { return { success: false, err: '密码错误' } } } } } catch (e) { console.log(e) return { success: false, err: '登陆失败,请联系管理员...' } } } module.exports = { login }
咱们在接口中生成token,将token返回客户端,客户端应在请求时携带此token,服务端根据token验证其身份。
在Koa中,咱们能够经过中间件的方式来实现请求拦截。
const jwt = require('jsonwebtoken') const secret = require('../config/secret.json') const util = require('util') const verify = util.promisify(jwt.verify) module.exports = function () { return async function (ctx, next) { // 设置接口白名单,不进行token验证 if (ctx.url === '/user/login') { await next() } else { try { let token = ctx.header.authorization // 获取请求携带的token if (token) { let payload try { payload = await verify(token.split(' ')[1].replace(/\s/g,''), secret.sign) // 解密payload,获取用户名和ID // 验证 合法性 // if (payload.exp <= new Date()/1000) { // console.log('过时了') // } await next() } catch (err) { ctx.body = {success: true, message: '登陆密钥失效或过时,请从新登陆', code: -1} console.log('token verify fail: ', err) } } else { ctx.body = {success: false, message: '验证失败', code: -1} } } catch (err) { console.log(err) } } } }
最后将中间件进行引入使用
必定在router以前
app.use(token()) app.use(router.routes())