1、安装jwt
npm i jsonwebtoken bcryptjs
npm i nanoid@3.3.6
2、config文件夹下新建index.js文件
const config = {
jwt: {
secret: 'urcq4yom', // jwt密钥
expiresIn: 60*60*262820
},
bcrypt: {
saltRounds: 12 // 生成salt迭代次数
},
crypto: {
JOINSTR: 'nm9sinr9' // md5拼接字符串
},
password:{
salt: 'r6pjidD6dpkKYY7U'
},
// 图形验证码
captcha:{
size: 4, // 验证码长度
ignoreChars: '012oOiILl', // 验证码字符中排除 0o1i
noise: 2, // 干扰线条的数量
fontSize: 52,
color: true, //开启文字颜色
// background:"#000",//背景色
width: 102,
height: 38,
time: 2*60,
}
}
module.exports = config
3、在utils文件夹下新建verify.js文件
const jwt = require('jsonwebtoken');
const config = require('../config');
const { LoginFailure } = require('../model/resModel')
// 生成token
const sign = (data) => {
return jwt.sign(data, config.jwt.secret, {
expiresIn: config.jwt.expiresIn,
});
};
// 验证token
const verify =async (ctx, next) => {
let authorization = ctx.headers.authorization || ctx.headers.Authorization || ctx.request.body.token || ctx.request.query.token || '';
let token = '';
if (authorization.includes('Bearer')) {
token = authorization.replace('Bearer ', '');
} else {
token = authorization;
}
try {
const res = jwt.verify(token, config.jwt.secret)
ctx.req.authData = res
await next();
} catch(error) {
ctx.body = new LoginFailure('token验证失败',error)
}
// });
};
module.exports = {
sign,
verify,
};
4、在utils文件夹下新建cryp.js文件
const crypto = require('crypto') // node 自带
const bcrypt = require('bcryptjs') // 需安装依赖 npm i bcryptjs
const { bcrypt: bcryptConfig, crypto: cryptoConfig } = require('../config')
// md5加密
function md5(v) {
const { JOINSTR } = cryptoConfig
return crypto.createHash('md5').update(v + JOINSTR).digest('hex')
}
// 密码加密
function encryptPassword(password) {
const { saltRounds } = bcryptConfig
const pwdEnCode = md5(password)
const salt = bcrypt.genSaltSync(saltRounds)
return bcrypt.hashSync(pwdEnCode, salt)
}
// 密码验证
function verifyPassword(inputPwd, userPwd) {
const pwdEnCode = md5(inputPwd)
return bcrypt.compareSync(pwdEnCode, userPwd)
}
module.exports = {
encryptPassword,
verifyPassword
}
5、在controller新建admin.js文件
const db = require('../config/knex')
const { encryptPassword,verifyPassword } = require('../utils/cryp')
const { sign } = require('../utils/verify')
const { SuccessModel, ErrorModel } = require('../model/resModel')
const adminModel = require('../model/adminModel')
class AdminController {
// 登录
async login(ctx, next) {
const { username, password } = ctx.request.body
const res = await adminModel.getInfo({username})
if(res.length===0) return ctx.body = new ErrorModel('没有该账号')
if (!verifyPassword(password + res[0].salt,res[0].password)) return ctx.body = new ErrorModel('密码错误')
delete res[0].password
delete res[0].salt
res[0].token = sign({ id: res[0].id,username: res[0].username,group_id:res[0].group_id })
try {
const time=new Date().getTime() / 1000
const updateRes = await adminModel.update(res[0].id,{token: res[0].token,login_time:time})
if(!updateRes) return ctx.body = new ErrorModel('登录错误')
ctx.body = new SuccessModel('登录成功',res[0])
} catch (error) {
return ctx.body = new ErrorModel(error)
}
}
}
module.exports = new AdminController()
6、在model文件夹下新建adminModel.js文件
const db = require('../config/knex')
class cms_adminModel {
async create(data){
return await db.create('cms_admin',data)
}
async getInfo(where){
return await db.knex('cms_admin')
.join('cms_auth_group', 'cms_admin.group_id', 'cms_auth_group.id')
.select('cms_admin.*','cms_auth_group.title','cms_auth_group.rules','cms_auth_group.roleCode')
.where(where)
}
async update(id,data){
return await db.update('cms_admin',id,data)
}
async delete(id){
return await db.remove('cms_admin',id)
}
async batchDelete(ids){
return await db.batchDelete('cms_admin',ids)
}
async page(page=1,size=10, where={},orderBy='',fields='*'){
const offset = (page - 1) * size;
const order = orderBy ? order : ['id' ,'desc'];
const query = db.knex('cms_admin').count('* as total')
.where('username', 'like',`%${where.username}%`)
.where('nickname', 'like',`%${where.nickname}%`)
.where('mobile', 'like',`%${where.mobile}%`)
const [countResult, rows] = await Promise.all([
query,
db.knex('cms_admin')
.select(fields)
.where(where)
.orderBy(order[0],order[1])
.offset(offset)
.limit(size)
]);
const count = countResult[0].total;
const pageData = {
page:Number(page),
size,
count,
list: rows
};
return pageData;
}
async list(where=[],fields='*'){
return await db.getList('cms_admin',where,fields)
}
}
module.exports = new cms_adminModel()
7、修改routes文件夹下的admin.js
const router = require('koa-router')()
const jwt = require('../../utils/verify')
const AdminController = require('../../controller/admin')
router.prefix('/api')
router.post('/system/user/login', AdminController.login)
module.exports = router
8、app.js中引入admin路由
const admin=require('./routes/admin/admin.js');
app.use(admin.routes(), admin.allowedMethods())
9、在数据库cms_admin新建一条数据,用来测试登录的接口
//数据库字段对应值 账号:admin 密码:123456
{
username:'admin',
nickname:'Admin',
password: '$2a$12$YPckpLQYEP1b5u2X/v5MG.y38u07TvCsd2tXqMxAZ72XTiM2RU65O',
salt: 'qONFQbo2AuApbnVLyWmd8',
group_id: 1
}
10、在数据库cms_auth_group新建一条数据,
{
title:'超级管理员',
status:1
}
11、使用apifox测试接口,post请求
http://localhost:3008/api/system/user/login
{
"username": "admin",
"password": "123456"
}
结果返回: