Koa2 token 鉴权
Token认证流程
-
- 客户端使用账号和密码进行登录
-
- 服务端获取用户登录请求后,进行验证
-
- 当验证通过之后,生成Token,并返回给客户端
-
- 客户端获取到Token并存储在 Web Storage 中
-
- 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
-
- 服务端收到请求,然后去验证客户端请求里面带着的 Token(request头部添加Authorization),如果验证成功,就向客户端返回请求的数据,如果不成功返回401错误码,鉴权失败,401表示没有访问权限,需要进行身份认证
jsonwebtoken 和 koa-jwt
- jsonwebtoken 用于生成token
- koa-jwt 为处理token的中间件
- 其中他们两个的密钥必须相同
- 安装
npm install jsonwebtoken koa-jwt -S
jsonwebtoken使用

const secret = "fl.b-18#cd_/12*+chan&koa^!.nam$milo"
const { sign } = require('jsonwebtoken')
const singToken = (data, time) => {
const token = sign(
data,
secret,
{
expiresIn: time
}
)
return token
}
module.exports = {
singToken,
secret
}

const {
exec,
escape
} = require('../db/mysql')
const { genPassword } = require('./../utils/cryp')
const xss = require('xss')
const checkIsRegister = async (username) => {
username = escape(username)
username = xss(username)
const sql = `
SELECT * from users WHERE username=${username}
`
const result = await exec(sql)
if (result.length) {
return true
}
return false
}
const register = async (name, username, password) => {
name = xss(escape(name))
username = xss(escape(username))
password = genPassword(password)
const sql = `
INSERT INTO users (name, username, password)
VALUES (${name}, ${username}, '${password}')
`
const result = await exec(sql)
return {
id: result.insertId
}
}
const login = async (username, password) => {
username = xss(escape(username))
password = genPassword(password)
const sql = `
SELECT id, name, username FROM users WHERE username=${username} AND password='${password}'
`
const result = await exec(sql)
return result
}
module.exports = {
checkIsRegister,
register,
login
}

const router = require('koa-router')()
const { checkIsRegister, register, login } = require('./../controller/users')
const { SuccessModel, ErrorModel } = require('./../model/resModel')
router.prefix('/users')
router.post('/register', async function (ctx, next) {
try {
const { name, username, password } = ctx.request.body
const isRegister = await checkIsRegister(username)
if (isRegister) {
ctx.body = new ErrorModel('该用户已被注册')
} else {
const registerResult = await register(name, username, password)
ctx.body = new SuccessModel(registerResult, '注册成功')
}
}catch {
ctx.body = new ErrorModel('注册失败')
}
})
router.post('/login', async ctx => {
try {
const { username, password } = ctx.request.body
const loginResult = await login(username, password)
if (loginResult.length) {
const data = {
userinfo: {
...loginResult[0]
},
token: 'token'
}
ctx.body = new SuccessModel(data, '登录成功')
} else {
ctx.body = new ErrorModel('登录失败')
}
}catch {
ctx.body = new ErrorModel('登录失败')
}
})
module.exports = router






koa-jwt使用
全局使用

const jwt = require('koa-jwt')
const { secret } = require('./utils/singToken')
const { ErrorModel } = require('./model/resModel')
app.use(function(ctx, next){
return next().catch((err) => {
if (401 == err.status) {
ctx.status = 401;
ctx.body = new ErrorModel('Protected resource, use Authorization header to get access')
} else {
throw err;
}
});
});
app.use(jwt({ secret }).unless({ path: [/^\/users/] }))
const Koa = require('koa')
const app = new Koa()
const json = require('koa-json')
const onerror = require('koa-onerror')
const bodyparser = require('koa-bodyparser')
const morgan = require('koa-morgan')
const path = require('path')
const fs = require('fs')
const cors = require('koa2-cors')
const jwt = require('koa-jwt')
const { secret } = require('./utils/singToken')
const { ErrorModel } = require('./model/resModel')
const index = require('./routes/index')
const users = require('./routes/users')
const uploads = require('./routes/upload')
const download = require('./routes/download')
const jwtTest = require('./routes/jwtTest')
onerror(app)
app.use(bodyparser({
enableTypes:['json', 'form', 'text']
}))
app.use(json())
app.use(require('koa-static')(__dirname + '/public/'))
app.use(cors({
origin: function(ctx) {
if (ctx.url === '/test') {
return false
}
return '*'
},
exposeHeaders: ['WWW-Authenticate', 'Server-Authorization'],
maxAge: 5,
credentials: true,
allowMethods: ['GET', 'POST', 'DELETE'],
allowHeaders: ['Content-Type', 'Authorization', 'Accept'],
}))
const ENV = process.env.NODE_ENV
if (ENV === 'dev') {
app.use(morgan('dev'))
} else {
const logFileName = path.join(__dirname, 'logs', 'access.log')
const writeStream = fs.createWriteStream(logFileName, {
flags: 'a'
})
app.use(morgan('combined', {
stream: writeStream
}));
}
app.use(function(ctx, next){
return next().catch((err) => {
if (401 == err.status) {
ctx.status = 401;
ctx.body = new ErrorModel('Protected resource, use Authorization header to get access')
} else {
throw err;
}
});
});
app.use(jwt({ secret }).unless({ path: [/^\/users/] }))
app.use(index.routes(), index.allowedMethods())
app.use(users.routes(), users.allowedMethods())
app.use(uploads.routes(), uploads.allowedMethods())
app.use(download.routes(), download.allowedMethods())
app.use(jwtTest.routes(), jwtTest.allowedMethods())
app.on('error', (err, ctx) => {
console.error('server error', err, ctx)
});
module.exports = app
- 测试,此处重新定义了一个新路由,用来测试jwt鉴权的效果,不传token






upload() {
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTIsIm5hbWUiOiJ0ZXN0MSIsInVzZXJuYW1lIjoidGVzdDEiLCJpYXQiOjE2MTkxNTc4MzcsImV4cCI6MTYxOTE5MzgzN30.-bUt82X5tCGMlmV46oHYzyC7wMvKxkdOfXxNPGBfniQ'
axios.interceptors.request.use(
config => {
if (token) {
config.headers.common["Authorization"] = "Bearer " + token
}
return config
},
err => {
return Promise.reject(err)
}
)
axios.post('http://localhost:3000/jwt-test').then(res => {
console.log(res)
})
}

局部中间件使用


- 路由配置,此处也是对 /jwt-test路由 进行jwt-koa中间使用




const router = require('koa-router')()
const { SuccessModel } = require('./../model/resModel')
const { secret } = require('./../utils/singToken')
const jwt = require('koa-jwt')
router.prefix('/jwt-test')
router.post('/', jwt({ secret }), async ctx => {
const userinfo = ctx.state.user
ctx.body = new SuccessModel(userinfo)
})
module.exports = router



token过期,也是相当于没有token,无法进行权限认证,就会返回401状态码,

