From adbf691a179cd5545f79fe8744e8c87c284f5125 Mon Sep 17 00:00:00 2001 From: vicanso Date: Sun, 28 Oct 2018 10:59:28 +0800 Subject: [PATCH] feat: support options.externalKey #88 --- Readme.md | 7 +++++ index.js | 6 +++++ lib/context.js | 17 +++++++++--- test/externalkey.test.js | 56 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 test/externalkey.test.js diff --git a/Readme.md b/Readme.md index efcd6e7..6a00431 100644 --- a/Readme.md +++ b/Readme.md @@ -127,6 +127,13 @@ console.log('listening on port 3000'); - `session:invalid`: session value is invalid. - `session:expired`: session value is expired. +### Custom External Key + +External key is used the cookie by default, but you can use `options.externalKey` to customize your own external key methods. `options.externalKey` with two methods: + +- `get(ctx)`: get the external key +- `set(ctx, value)`: set the external key + ### Session#isNew Returns __true__ if the session is new. diff --git a/index.js b/index.js index 7cb9edc..606ab13 100644 --- a/index.js +++ b/index.js @@ -88,6 +88,12 @@ function formatOpts(opts) { assert(is.function(store.destroy), 'store.destroy must be function'); } + const externalKey = opts.externalKey; + if (externalKey) { + assert(is.function(externalKey.get), 'externalKey.get must be function'); + assert(is.function(externalKey.set), 'externalKey.set must be function'); + } + const ContextStore = opts.ContextStore; if (ContextStore) { assert(is.class(ContextStore), 'ContextStore must be a class'); diff --git a/lib/context.js b/lib/context.js index 90c0c32..410996b 100644 --- a/lib/context.js +++ b/lib/context.js @@ -70,8 +70,15 @@ class ContextSession { const ctx = this.ctx; const opts = this.opts; - const externalKey = ctx.cookies.get(opts.key, opts); - debug('get external key from cookie %s', externalKey); + let externalKey; + if (opts.externalKey) { + externalKey = opts.externalKey.get(ctx); + debug('get external key from custom %s', externalKey); + } else { + externalKey = ctx.cookies.get(opts.key, opts); + debug('get external key from cookie %s', externalKey); + } + if (!externalKey) { // create a new `externalKey` @@ -309,7 +316,11 @@ class ContextSession { changed, rolling: opts.rolling, }); - this.ctx.cookies.set(key, externalKey, opts); + if (opts.externalKey) { + opts.externalKey.set(this.ctx, externalKey); + } else { + this.ctx.cookies.set(key, externalKey, opts); + } return; } diff --git a/test/externalkey.test.js b/test/externalkey.test.js new file mode 100644 index 0000000..c3625cb --- /dev/null +++ b/test/externalkey.test.js @@ -0,0 +1,56 @@ +'use strict'; +const Koa = require('koa'); +const request = require('supertest'); +const assert = require('assert'); +const session = require('..'); +const store = require('./store'); +const TOKEN_KEY = 'User-Token'; +describe('Koa Session External Key', () => { + describe('when the external key set/get is invalid', () => { + it('should throw a error', () => { + try { + new App({ + externalKey: {}, + }); + } catch (err) { + assert.equal(err.message, 'externalKey.get must be function'); + } + }); + }); + describe('custom get/set external key', () => { + it('should still work', done => { + const app = App(); + app.use(async function(ctx) { + if (ctx.method === 'POST') { + ctx.session.string = ';'; + ctx.status = 204; + } else { + ctx.body = ctx.session.string; + } + }); + const server = app.listen(); + request(server) + .post('/') + .expect(204, (err, res) => { + if (err) return done(err); + const token = res.get(TOKEN_KEY); + request(server) + .get('/') + .set(TOKEN_KEY, token) + .expect(';', done); + }); + }); + }); +}); +function App(options) { + const app = new Koa(); + app.keys = [ 'a', 'b' ]; + options = options || {}; + options.store = store; + options.externalKey = options.externalKey || { + get: ctx => ctx.get(TOKEN_KEY), + set: (ctx, value) => ctx.set(TOKEN_KEY, value), + }; + app.use(session(options, app)); + return app; +}