-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
119 lines (111 loc) · 2.68 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
const jwt = require('jsonwebtoken');
const helper = require('think-helper');
const assert = require('assert');
const sign = helper.promisify(jwt.sign, jwt);
const verify = helper.promisify(jwt.verify, jwt);
const callback = any => any;
class JWTSession {
/**
* @constructor
* @param {object} options - config
* @param {object} ctx - koa context
*/
constructor(options, ctx) {
assert(options && options.secret, 'jwt secret is required');
this.options = options;
this.ctx = ctx;
this.data = {};
this.fresh = true;
this.error = null;
this.verifyCallback = options.verifyCallback || callback;
this.verifyOptions = options.verify || {};
this.signOptions = options.sign || {};
}
/**
* init session data
*/
async initSessionData() {
if (this.fresh) {
let token;
const { tokenType = 'cookie', tokenName = 'jwt' } = this.options;
switch (tokenType) {
case 'header':
token = this.ctx.headers[tokenName];
break;
case 'body':
token = this.ctx.post(tokenName);
break;
case 'query':
token = this.ctx.query[tokenName];
break;
default:
token = this.ctx.cookie(tokenName, undefined, this.options);
break;
}
if (token) {
try {
this.data = await verify(
token,
this.options.secret,
this.verifyOptions
);
} catch (err) {
this.error = this.verifyCallback(err) || err;
} finally {
this.fresh = false;
}
}
}
}
/**
* auto save session data when it is change
*/
async autoSave() {
const data = helper.extend({}, this.data);
delete data.exp;
delete data.iat;
delete data.nbf;
delete data.aud;
delete data.sub;
delete data.iss;
delete data.jti;
delete data.alg;
const token = await sign(data, this.options.secret, this.signOptions);
return token;
}
/**
* get session value
* @param {string} name
* @return {Promise} value
*/
async get(name) {
await this.initSessionData();
if (this.error) {
return this.error;
}
return name ? this.data[name] : this.data;
}
/**
* set session value
* @param {string} name
* @param {string} value
* @return {Promise} resolved
*/
async set(name, value) {
await this.initSessionData();
if (name) {
this.data[name] = value;
}
const token = await this.autoSave();
return token;
}
/**
* delete session
* @return {Promise} resolved
*/
async delete() {
await this.initSessionData();
this.data = {};
}
}
module.exports = JWTSession;