在web应用中,我们常常使用session来管理会话,用一个sessionId来表明用户已登录。session结合cookie管理会话在web应用中是很常见的。
在koa项目中
npm install koa-session2
//app.js
const Koa = require('koa')
const app = new Koa()
const views = require('koa-views')
const json = require('koa-json')
const onerror = require('koa-onerror')
const bodyparser = require('koa-bodyparser')
const logger = require('koa-logger')
const session = require("koa-session2");
const index = require('./routes/index')
const users = require('./routes/users')
const Store = require("./src/store/store");
//session
app.use(session({
store:new Store()
}))
// error handler
onerror(app)
// middlewares
app.use(bodyparser({
enableTypes:['json', 'form', 'text']
}))
app.use(json())
app.use(logger())
app.use(require('koa-static')(__dirname + '/public'))
app.use(views(__dirname + '/views', {
extension: 'pug'
}))
//登陆拦截
app.use(async (ctx, next) => {
if(!ctx.cookies.get('koa:sess') && ctx.path !== '/users/login'){
console.log(ctx.cookies.get('koa:sess'),ctx.path)
await ctx.render('index',{
title:'请登录'
})
return;
}
next()
})
// logger
app.use(async (ctx, next) => {
const start = new Date()
await next()
const ms = new Date() - start
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
})
// routes
app.use(index.routes(), index.allowedMethods())
app.use(users.routes(), users.allowedMethods())
// error-handling
app.on('error', (err, ctx) => {
console.error('server error', err, ctx)
});
module.exports = app
//store.js
const Redis = require("ioredis");
const { Store } = require("koa-session2");
class RedisStore extends Store {
constructor() {
super();
this.redis = new Redis({
port: 6379, // Redis port
host: '', // Redis host
family: 4, // 4 (IPv4) or 6 (IPv6)
password: '',
db: 0
});
}
async get(sid, ctx) {
let data = await this.redis.get(`SESSION:${sid}`);
return JSON.parse(data);
}
async set(session, { sid = this.getID(24), maxAge = 1000000 } = {}, ctx) {
try {
// Use redis set EX to automatically drop expired sessions
await this.redis.set(`SESSION:${sid}`, JSON.stringify(session), 'EX', maxAge / 1000);
} catch (e) {}
return sid;
}
async destroy(sid, ctx) {
return await this.redis.del(`SESSION:${sid}`);
}
}
module.exports = RedisStore;
如上我们用一个store来继承session中的koa-session2中的store,主要是将sessionid持久化到redis中,本文使用了ioredis来连接redis数据库。
然后当ctx的session改变的时候会触发koa-session2中的方法,
const router = require('koa-router')()
router.prefix('/users')
router.get('/', function (ctx, next) {
ctx.body = 'this is a users response!'
})
router.get('/bar', function (ctx, next) {
ctx.body = 'this is a users/bar response'
})
router.get('/login', function (ctx, next) {
ctx.session.user = JSON.stringify({userName:'Daming:'+Math.random(),'age':18})
ctx.render('index', {
title: 'Hello Koa 2!'
})
})
router.get('/logout', function (ctx, next) {
ctx.session = {};
ctx.render('index', {
title: '请登录'
})
})
module.exports = router
如上所示 我们登录成功之后可以把用户信息存入session中。koa-session2会将sessionId写入cookie,再把session对象写入redis,键值为sessionID,这样每次客户端的请求带上sessionID我们就可以从redis中取登录用户信息。也可以通过是否有sessionID来做会话拦截。
退出的时候只要将ctx.session置为{}就可以了。