From 04867d02e82352bb36cbaec229435d1800778413 Mon Sep 17 00:00:00 2001 From: felixpy Date: Wed, 19 Dec 2018 21:29:37 +0800 Subject: [PATCH 1/2] core: support for separate application configuration --- README.md | 2 +- app/middleware/token.js | 18 +++-- config/config.default.js | 5 +- package.json | 2 +- .../apps/token-test/config/config.default.js | 12 +++- test/token.test.js | 65 ++++++++++++++++--- 6 files changed, 87 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index ecebf0d..18d72d4 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ const hash = crypto.createHash('md5'); const APP_CODE = 'felixpy'; const APP_SECRET = 'your-magic-secret-key'; -const ts = new Date().getTime(); +const ts = Date.now(); const md5Value = hash.update(`${APP_CODE}:${ts}:${APP_SECRET}`).digest('hex'); const token = Buffer.from(`${APP_CODE}:${ts}:${md5Value}`).toString('base64'); diff --git a/app/middleware/token.js b/app/middleware/token.js index a709aac..41c2c98 100644 --- a/app/middleware/token.js +++ b/app/middleware/token.js @@ -2,8 +2,13 @@ const crypto = require('crypto'); -function checkToken(type, secret, token) { - const [ code, ts, auth ] = token.split(':'); +function checkToken(type, { code, ts, auth }, { secret, expires }) { + const now = Date.now(); + + if (now - ts > expires) { + return false; + } + const hash = crypto.createHash(type); hash.update(`${code}:${ts}:${secret}`); @@ -12,11 +17,12 @@ function checkToken(type, secret, token) { } module.exports = (options, app) => { - const { type, secret } = options; + const { type, apps } = options; return async function search(ctx, next) { const base64Token = ctx.get('egg-api-token') || ''; const token = Buffer.from(base64Token, 'base64').toString(); + const [ code, ts, auth ] = token.split(':'); app.loggers.coreLogger.info( '[egg-token] checking api token %s -> %s', @@ -24,7 +30,11 @@ module.exports = (options, app) => { token ); - if (!token || !checkToken(type, secret, token)) { + if ( + !token || + !apps[code] || + !checkToken(type, { code, ts, auth }, apps[code]) + ) { ctx.throw(401, 'Unauthorized'); } diff --git a/config/config.default.js b/config/config.default.js index 5d37afc..135f2b4 100644 --- a/config/config.default.js +++ b/config/config.default.js @@ -4,9 +4,10 @@ * egg-token default config * @member Config#token * @property {String} type - encryption algorithm - * @property {String} secret - secret key + * @property {Object} apps - authorized applications */ exports.token = { type: 'md5', - secret: 'your-magic-secret-key', + + apps: {}, }; diff --git a/package.json b/package.json index 35a3fd0..836a6c3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "egg-token", - "version": "1.0.2", + "version": "2.0.0", "description": "Egg.js middleware that uses encrypted token to authenticate.", "eggPlugin": { "name": "token" diff --git a/test/fixtures/apps/token-test/config/config.default.js b/test/fixtures/apps/token-test/config/config.default.js index 00c8463..711a53e 100644 --- a/test/fixtures/apps/token-test/config/config.default.js +++ b/test/fixtures/apps/token-test/config/config.default.js @@ -4,7 +4,17 @@ exports.middleware = [ 'token' ]; exports.token = { type: 'md5', - secret: 'XnMib79vzwP01gtr', + + apps: { + felixpy: { + secret: 'XnMib79vzwP01gtr', + expires: 30000, + }, + codetrial: { + secret: 'mi9yNGT6zwrqMv8z', + expires: 30000, + }, + }, }; exports.keys = 'egg-token'; diff --git a/test/token.test.js b/test/token.test.js index 2ef6e32..0faa4d8 100644 --- a/test/token.test.js +++ b/test/token.test.js @@ -3,6 +3,13 @@ const crypto = require('crypto'); const mock = require('egg-mock'); +const createToken = function(code, ts, secret) { + const hash = crypto.createHash('md5'); + const md5Value = hash.update(`${code}:${ts}:${secret}`).digest('hex'); + + return Buffer.from(`${code}:${ts}:${md5Value}`).toString('base64'); +}; + describe('test/token.test.js', () => { let app; before(() => { @@ -22,15 +29,57 @@ describe('test/token.test.js', () => { .expect(401); }); - it('should GET /', () => { - const hash = crypto.createHash('md5'); - const code = 'felixpy'; - const ts = new Date().getTime(); - const md5Value = hash - .update(`${code}:${ts}:XnMib79vzwP01gtr`) - .digest('hex'); + it('should return unauthorized with wrong secret', () => { + const token = createToken('felixpy', Date.now(), 'SomeWrongSecret'); + + return app + .httpRequest() + .get('/') + .set('egg-api-token', token) + .expect(401); + }); + + it('should return unauthorized with wrong application', () => { + const token = createToken('ypxilef', Date.now(), 'XnMib79vzwP01gtr'); + + return app + .httpRequest() + .get('/') + .set('egg-api-token', token) + .expect(401); + }); + + it('should return unauthorized with wrong timestamp', () => { + const token = createToken( + 'felixpy', + Date.now() - 30001, + 'XnMib79vzwP01gtr' + ); + + return app + .httpRequest() + .get('/') + .set('egg-api-token', token) + .expect(401); + }); + + it('should authorized with valid timestamp', () => { + const token = createToken( + 'felixpy', + Date.now() - 20000, + 'XnMib79vzwP01gtr' + ); + + return app + .httpRequest() + .get('/') + .set('egg-api-token', token) + .expect('hi, token') + .expect(200); + }); - const token = Buffer.from(`${code}:${ts}:${md5Value}`).toString('base64'); + it('should authorized with app ', () => { + const token = createToken('felixpy', Date.now(), 'XnMib79vzwP01gtr'); return app .httpRequest() From 9dd34349011ca1103ecea422b551efa74004c99a Mon Sep 17 00:00:00 2001 From: felixpy Date: Wed, 19 Dec 2018 21:43:32 +0800 Subject: [PATCH 2/2] docs: update config and example --- README.md | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 18d72d4..cf17b6b 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,17 @@ exports.middleware = ['token']; exports.token = { type: 'md5', - secret: 'your-magic-secret-key' + + apps: { + felixpy: { + secret: 'XnMib79vzwP01gtr', + expires: 30000 + }, + codetrial: { + secret: 'mi9yNGT6zwrqMv8z', + expires: 30000 + } + } }; ``` @@ -41,6 +51,16 @@ exports.token = { See [crypto.createHash](https://nodejs.org/api/crypto.html#crypto_crypto_createhash_algorithm_options) for more detail. +Each key of `apps` is the application's code, `secret` is used to generate token and `expires` is the validity period of the token. + +The way to generate tokens is as follows: + +```js +const ts = Date.now(); +const md5Value = md5(`${APP_CODE}:${ts}:${APP_SECRET}`); +const token = base64Encode(`${APP_CODE}:${ts}:${md5Value}`); +``` + ## Example This is an example of using axios to request an api: @@ -52,7 +72,7 @@ const axios = require('axios'); const hash = crypto.createHash('md5'); const APP_CODE = 'felixpy'; -const APP_SECRET = 'your-magic-secret-key'; +const APP_SECRET = 'XnMib79vzwP01gtr'; const ts = Date.now(); const md5Value = hash.update(`${APP_CODE}:${ts}:${APP_SECRET}`).digest('hex');