创建项目
- 安装Koa脚手架
npm install -g koa-generator
- 生成项目
koa -e koa2_learn or koa koa2_learn
配置中间件
- 配置cors 跨域中间件
npm i koa2-cors
const cors = require('koa2-cors')
app.use(cors())
- 配置swagger装饰的路由
npm install koa2-swagger-ui
npm install swagger-jsdoc
新建utils/swagger.js
const router = require('koa-router')() //引入路由函数
const path = require('path')
const swaggerJSDoc = require('swagger-jsdoc')
const swaggerDefinition = {
info: {
title: 'koa服务端API',
version: '1.0.0',
description: 'koa服务端API接口文档'
},
host: 'localhost:3000', // 接口文档访问地址为:localhost:3000/swagger
basePath: '/' // Base path (optional)
}
const options = {
swaggerDefinition,
apis: [path.join(__dirname, './routes/*.js')] // 写有注解的router的存放地址, 最好path.join()
}
const swaggerSpec = swaggerJSDoc(options)
// 通过路由获取生成的注解文件
router.get('/swagger.json', async function (ctx) {
ctx.set('Content-Type', 'application/json')
ctx.body = swaggerSpec
})
module.exports = router
- 在app.js注册KoaSwagger中间件
const { koaSwagger } = require('koa2-swagger-ui')
// 引入总路由
const routes = require('./routes')
注册中间件
.use(
koaSwagger({
routePrefix: '/swagger', // 接口文档访问地址
swaggerOptions: {
url: '/swagger.json' // example path to json 其实就是之后swagger-jsdoc生成的文档地址
}
})
routes(app) // 挂载路由
路由模块
- routrs/index.js 自动导入所有子路由模块
/*
*所有的路由接口
*/
const fs = require('fs')
module.exports = (app)=>{
fs.readdirSync(__dirname).forEach(file=>{
if(file === 'index.js'){
return
}
const router = require(`./${file}`)
app.use(router.routes()).use(router.allowedMethods())
})
}
- routes/users.js
// const Router = require('koa-router')
// const router = new Router()
// 引入经过 swagger 装饰的 router
const router = require('../utils/swagger')
// 设置统一前缀
router.prefix('user')
//用户相关的处理函数
const {
login,
register,
getUserInfo,
updateUserInfo,
updatePassword,
updateAvatar
} = require('../controller/users')
//数据验证
const koaJoi = require('../validator')
const {
reg_login_schema,
update_userinfo_schema,
update_password_schema,
update_avatar_schema
} = require('../validator/user')
//用户登录
router.post('/login', koaJoi('post', reg_login_schema), login)
//用户注册
router.post('/reguser', koaJoi('post', reg_login_schema), register)
//获取用户信息
router.get('/userinfo', getUserInfo)
//更新用户的基本信息
router.post('/userinfo', updateUserInfo)
// 重置密码
router.post('/updatepwd', updatePassword)
// 更新用户头像
router.post('/update/avatar', updateAvatar)
module.exports = router
安装连接mysql数据库
npm install --save mysql
- 新建db/index.js
const mysql = require('mysql')
function connect() {
return mysql.createConnection({
host: '127.0.0.1',
user: 'zoe',
password: '123456',
database: 'zoe',
connectionLimit: 5
})
}
const sqlconnection = (sql, parmas = null) => {
// 获取数据库链接对象
const conn = connect()
return new Promise(function (resolve, reject) {
// 执行SQL语句
try {
conn.query(sql, parmas, (err, results) => {
if (err) {
reject(err)
} else {
resolve(results)
}
})
} catch (e) {
reject(e)
} finally {
conn.end() // 关闭链接
}
})
}
module.exports = { sqlconnection }
用户注册API
// 用于密码加密
npm install --save bcryptjs
const db = require('../db')
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
const { jwtSecret, expiresIn } = require('../config')
const CONSTANT = require('../config/constant')
//用户注册
exports.register = async (ctx) => {
let req = ctx.request
//获取请求体数据
const userinfo = req.body
const sqlStr = `select * from users where username=?`
const results = await db.sqlconnection(sqlStr, [userinfo.username])
// 用户名被占用
if (results.length > 0)
return responseClient(ctx, RES_CODE.dataFail, '用户名已存在,请更换其他用户名')
// 密码进行加密处理
userinfo.password = bcrypt.hashSync(userinfo.password, 10)
// console.log('加密后', userinfo)
// 插入用户
const sql = 'insert into users set ?'
// 验证通过 将数据保存到数据库
const res = await db.sqlconnection(sql, {
username: userinfo.username,
password: userinfo.password
})
// sql语句执行成功,但影响行数不为1
if (res.affectedRows !== 1) {
return responseClient(ctx, RES_CODE.dataFail, '注册用户失败,请稍后再试!')
}
responseClient(ctx, RES_CODE.reqSuccess, '注册成功')
}
// responseClient 该方法为封装的统一返回方法
用户登录API
// 用于token
npm i jsonwebtoken koa-jwt
- 在config/index.js 下配置 token 密钥和有效期
// 秘钥取自 UUID
module.exports = {
// token 秘钥
jwtSecret: '860450f9f4ff1ad59019f7ff4909021a',
//token 有效期
expiresIn: '10h',
port: 3000
}
//用户登录
exports.login = async (ctx) => {
let req = ctx.request
const userinfo = req.body
// console.log('userinfo', userinfo)
// 根据用户名查询用户数据
const sqlStr = `select * from users where username=?`
const results = await db.sqlconnection(sqlStr, userinfo.username)
if (results.length !== 1) return responseClient(ctx, RES_CODE.dataFail, '登录失败')
// 密码对比
const compareResult = bcrypt.compareSync(
userinfo.password, //用户提交的密码
results[0].password //数据库中的密码
)
if (!compareResult) return responseClient(ctx, RES_CODE.dataFail, '用户名或密码错误')
const user = { ...results[0], password: '', user_pic: '' }
console.log('user', user)
const tokenStr = jwt.sign(user, jwtSecret, { expiresIn: expiresIn })
let data = {
user: user,
token: `Bearer ${tokenStr}`
}
responseClient(ctx, RES_CODE.reqSuccess, '登录成功', data)
}
注册,登录时字段验证
npm install joi
- 新建validator/index.js 封装验证方法函数
function schema(method, schemas) {
async function validateSchema(ctx, next) {
let data = null
if (method === 'get') {
data = await ctx.request.query
} else {
data = await ctx.request.body
}
const { error } = schemas.validate(data)
if (error) {
ctx.body = error.message
// severErr(error)
return
}
await next()
}
return validateSchema
}
module.exports = schema
- 在validator/user.js 统一管理用户相关的验证字段
const joi = require('joi')
/**
*string()值必须是字符串
*alphanum()值只能是包含a-zA-Z0-9的字符串
*min(length)最小长度*max(length)最大长度
*required()值是必填项,不能为undefined
*pattern(正则表达式)值必须符合正则表达式的规则
* */
//用户名的验证规则
const username = joi.string().alphanum().min(1).max(10).required()
//密码的验证规则
const password = joi
.string()
.pattern(/^[\S]{6,12}$/)
.required()
//定义id,nickname,emial的验证规则
const id = joi.number().integer().min(1).required()
const nickname = joi.string().required()
const email = joi.string().email().required()
//dataUri()指的是如下格式的字符串数据:
//data:image/png;base64,VE9PTUFOWVNFQ1JFVFM=
const avatar = joi.string().dataUri().required()
// 比如注册登入只需验证用户名和密码这两个字段
exports.reg_login_schema = joi.object({
username,
password
})
// 更新用户基本信息
exports.update_userinfo_schema = joi.object{{
id,
nickname,
email
}}
- 在路由users模块使用
//数据验证
const koaJoi = require('../validator')
//用户登录
router.post('/login', koaJoi('post', reg_login_schema), login)
//用户注册
router.post('/reguser', koaJoi('post', reg_login_schema), register)
路由鉴权
- 新建utils/jwt.js 配置路由权限中间件实现对非登录和注册API需要Token认证
//解析token的中间件
// const expressJwt = require('express-jwt')
const koaJwt = require('koa-jwt')
const { jwtSecret } = require('../config/index')
module.exports = koaJwt({
secret: jwtSecret, //携带私钥
algorithms: ['HS256'], // 默认值
credentialsRequired: true // 设置为false就不进行校验了,游客也可以访问
}).unless({
path: [
// '/',
'/login',
'/reguser'
] // 设置 jwt 认证白名单
})
- 在app.js注册jwt中间件
//解析token的中间件
const jwtAuth = require('./utils/jwt')
// 挂载在路由之前
app.use(jwtAuth)