mm_njwt 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +152 -0
- package/example/index.js +38 -0
- package/package.json +38 -33
- package/test.js +11 -11
package/README.md
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# mm_njwt
|
|
2
|
+
|
|
3
|
+
mm_njwt 是一个基于 Node.js `crypto` 模块实现的 JWT(JSON Web Token)加解密库,用于在通信中生成、签名、解析和验证 JWT。它支持 HMAC、RSA、ECDSA 等多种签名算法及 `none` 无签名模式,提供链式设置 Claims 的 `Jwt` 构建器与可配置密钥解析器的 `Verifier` 验证器,适合用于接口鉴权、令牌签发与校验等场景。
|
|
4
|
+
|
|
5
|
+
## 项目信息
|
|
6
|
+
|
|
7
|
+
- **当前版本**: 1.0.1
|
|
8
|
+
- **更新日期**: 2026-10-04
|
|
9
|
+
- **Gitee地址**: https://gitee.com/qiuwenwu91/mm_njwt
|
|
10
|
+
- **依赖**:
|
|
11
|
+
- ecdsa-sig-formatter ^1.0.11(ECDSA 签名 DER/JOSE 格式转换)
|
|
12
|
+
- secure-random ^1.1.2(生成随机签名密钥)
|
|
13
|
+
- uuid ^11.1.0(生成默认 jti 声明)
|
|
14
|
+
|
|
15
|
+
## 特点
|
|
16
|
+
|
|
17
|
+
- 支持 HS256/384/512、RS256/384/512、ES256/384/512 及 `none` 共 10 种签名算法。
|
|
18
|
+
- 链式 API 设置标准 Claims(`jti`、`sub`、`iss`、`iat`、`exp`、`nbf`)及自定义 Claims、自定义 Header 字段。
|
|
19
|
+
- 创建 Token 时默认自动填充 `jti`(UUID v4)、`iat`(当前秒级时间戳),`create()` 默认 1 小时过期。
|
|
20
|
+
- 验证时自动校验签名算法一致性、过期时间(exp)、生效时间(nbf)与签名正确性。
|
|
21
|
+
- 支持通过 `setKeyResolver` / `withKeyResolver` 按 Header 中的 `kid` 动态解析验签密钥。
|
|
22
|
+
- 核心类与原型已 `Object.freeze` 冻结,防止运行时被篡改(对应 njwt 已知漏洞 SNYK-JS-NJWT-6861582)。
|
|
23
|
+
|
|
24
|
+
## 安装
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install mm_njwt
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 基本使用
|
|
31
|
+
|
|
32
|
+
```javascript
|
|
33
|
+
const nJwt = require('mm_njwt');
|
|
34
|
+
|
|
35
|
+
// 1. 创建并签名 Token(默认 HS256,自动设置 1 小时过期)
|
|
36
|
+
const claims = {
|
|
37
|
+
iss: 'http://myapp.com/', // 签发者
|
|
38
|
+
sub: 'users/user1234', // 用户标识
|
|
39
|
+
scope: 'self, admins'
|
|
40
|
+
};
|
|
41
|
+
const jwt = nJwt.create(claims, 'my-secret-key');
|
|
42
|
+
const token = jwt.compact(); // 得到 xxx.yyy.zzz 形式的 JWT 字符串
|
|
43
|
+
|
|
44
|
+
// 2. 验证 Token
|
|
45
|
+
nJwt.verify(token, 'my-secret-key', (err, verifiedJwt) => {
|
|
46
|
+
if (err) {
|
|
47
|
+
console.error('验证失败:', err.userMessage || err.message);
|
|
48
|
+
} else {
|
|
49
|
+
console.log('验证通过:', verifiedJwt.body);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## API 说明
|
|
55
|
+
|
|
56
|
+
### 顶层函数
|
|
57
|
+
|
|
58
|
+
| 方法 | 签名 | 返回值 | 说明 |
|
|
59
|
+
| --- | --- | --- | --- |
|
|
60
|
+
| create | `create(claims, secret, [alg])` | `Jwt` 实例 | 快速创建 Token。`claims` 为声明对象;`secret` 为签名密钥(`alg` 为 `'none'` 时可省略);`alg` 默认 `'HS256'`。自动设置 1 小时过期。若传入单个字符串参数,则视为密钥并创建空 Claims 的 Token |
|
|
61
|
+
| verify | `verify(jwtTokenString, [signingKey], [algOverride], [callback])` | 无回调时返回 `Jwt`,失败抛异常 | 便捷验证函数。内部创建 `Verifier`:传 2 参时按默认 HS256 验证;传 3 参时可覆盖签名算法;仅 1 参时按 `none` 验证 |
|
|
62
|
+
| createVerifier | `createVerifier()` | `Verifier` 实例 | 创建一个验证器实例 |
|
|
63
|
+
| base64urlEncode | `base64urlEncode(data)` | `String` | 将字符串(或数字)编码为 base64url 格式 |
|
|
64
|
+
| base64urlUnescape | `base64urlUnescape(str)` | `String` | 将 base64url 字符串还原为标准 base64(补齐 `=` 并替换 `-`、`_`) |
|
|
65
|
+
|
|
66
|
+
### Jwt 类
|
|
67
|
+
|
|
68
|
+
构造函数:`new nJwt.Jwt(claims, [enforceDefaultFields])`。`claims` 为声明对象;`enforceDefaultFields` 默认为 `true`,会自动补全 `typ=JWT`、`alg=none`、`jti`、`iat`,传 `false` 则不补全。实例属性 `header`(JwtHeader)与 `body`(JwtBody)可直接读取。
|
|
69
|
+
|
|
70
|
+
| 方法 | 签名 | 返回值 | 说明 |
|
|
71
|
+
| --- | --- | --- | --- |
|
|
72
|
+
| setClaim | `setClaim(claim, value)` | `this` | 设置任意自定义 Claim |
|
|
73
|
+
| setHeader | `setHeader(param, value)` | `this` | 设置 Header 自定义字段(如 `kid`) |
|
|
74
|
+
| setJti | `setJti(jti)` | `this` | 设置 Token 唯一标识 `jti` |
|
|
75
|
+
| setSubject | `setSubject(sub)` | `this` | 设置主题 `sub` |
|
|
76
|
+
| setIssuer | `setIssuer(iss)` | `this` | 设置签发者 `iss` |
|
|
77
|
+
| setIssuedAt | `setIssuedAt(iat)` | `this` | 设置签发时间(秒级时间戳) |
|
|
78
|
+
| setExpiration | `setExpiration(exp)` | `this` | 设置过期时间,接受 `Date` 或可被 `new Date()` 解析的值;传假值则删除 `exp` |
|
|
79
|
+
| setNotBefore | `setNotBefore(nbf)` | `this` | 设置生效时间,用法同 `setExpiration`;传假值则删除 `nbf` |
|
|
80
|
+
| setSigningKey | `setSigningKey(key)` | `this` | 设置签名密钥 |
|
|
81
|
+
| setSigningAlgorithm | `setSigningAlgorithm(alg)` | `this` | 设置签名算法,不支持的算法抛 `JwtError` |
|
|
82
|
+
| compact | `compact()` | `String` | 生成并返回完整 JWT 字符串。算法非 `none` 且未设置密钥时抛异常 |
|
|
83
|
+
| toString | `toString()` | `String` | 等价于 `compact()` |
|
|
84
|
+
| isExpired | `isExpired()` | `Boolean` | 是否已过期(依据 `exp`) |
|
|
85
|
+
| isNotBefore | `isNotBefore()` | `Boolean` | 是否尚未生效(依据 `nbf`) |
|
|
86
|
+
| sign | `sign(payload, algorithm, cryptoInput)` | `String` | 底层签名方法:对 `payload` 用 `algorithm` 和密钥 `cryptoInput` 签名,ECDSA 结果自动转为 JOSE 格式 |
|
|
87
|
+
| isSupportedAlg | `isSupportedAlg(alg)` | `Boolean` | 判断算法是否受支持 |
|
|
88
|
+
|
|
89
|
+
### Verifier 类
|
|
90
|
+
|
|
91
|
+
构造函数:`new nJwt.Verifier()`(或 `nJwt.createVerifier()`)。默认算法 `HS256`,默认密钥解析器返回自身 `signingKey`。
|
|
92
|
+
|
|
93
|
+
| 方法 | 签名 | 返回值 | 说明 |
|
|
94
|
+
| --- | --- | --- | --- |
|
|
95
|
+
| setSigningAlgorithm | `setSigningAlgorithm(alg)` | `this` | 指定期望的签名算法,与 Token Header 中 `alg` 不一致时验证失败 |
|
|
96
|
+
| setSigningKey | `setSigningKey(keyStr)` | `this` | 设置验签密钥 |
|
|
97
|
+
| setKeyResolver | `setKeyResolver(resolver)` | `undefined` | 设置密钥解析器,签名为 `resolver(kid, cb)`,通过 `cb(err, key)` 返回密钥 |
|
|
98
|
+
| withKeyResolver | `withKeyResolver(resolver)` | `this` | 链式设置密钥解析器 |
|
|
99
|
+
| verify | `verify(jwtString, [callback])` | 无回调时返回 `Jwt` | 验证 JWT 字符串:依次校验算法一致性、`exp`、`nbf`、签名。失败时通过回调返回 `JwtParseError`(含 `userMessage`、`jwtString`、`parsedHeader`、`parsedBody`),无回调则抛异常;成功后回调 `(null, jwt)` |
|
|
100
|
+
|
|
101
|
+
### JwtBody / JwtHeader
|
|
102
|
+
|
|
103
|
+
| 类 | 构造 | 方法 | 说明 |
|
|
104
|
+
| --- | --- | --- | --- |
|
|
105
|
+
| JwtBody | `new nJwt.JwtBody(claims)` | `toJSON()` 返回普通对象;`compact()` 返回 base64url 编码的 JSON 字符串 | JWT 载荷部分 |
|
|
106
|
+
| JwtHeader | `new nJwt.JwtHeader(header, [enforceDefaultFields])` | `compact()` 返回 base64url 编码的 JSON 字符串 | JWT 头部部分,保留字段为 `typ`、`alg` |
|
|
107
|
+
|
|
108
|
+
## 使用示例
|
|
109
|
+
|
|
110
|
+
### 场景一:完整控制 Claims 与 Header
|
|
111
|
+
|
|
112
|
+
```javascript
|
|
113
|
+
const nJwt = require('mm_njwt');
|
|
114
|
+
|
|
115
|
+
const jwt = new nJwt.Jwt({ uid: 1001 });
|
|
116
|
+
jwt.setIssuer('http://myapp.com/')
|
|
117
|
+
.setSubject('users/1001')
|
|
118
|
+
.setExpiration(new Date(Date.now() + 2 * 3600 * 1000)) // 2 小时后过期
|
|
119
|
+
.setHeader('kid', 'key-2026')
|
|
120
|
+
.setSigningAlgorithm('HS512')
|
|
121
|
+
.setSigningKey('strong-secret');
|
|
122
|
+
|
|
123
|
+
const token = jwt.compact();
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 场景二:按 kid 动态解析密钥验证
|
|
127
|
+
|
|
128
|
+
```javascript
|
|
129
|
+
const nJwt = require('mm_njwt');
|
|
130
|
+
|
|
131
|
+
const verifier = nJwt.createVerifier().withKeyResolver((kid, cb) => {
|
|
132
|
+
// 根据 header 中的 kid 查找对应密钥
|
|
133
|
+
const key = kid === 'key-2026' ? 'strong-secret' : null;
|
|
134
|
+
cb(key ? null : new Error('key not found'), key);
|
|
135
|
+
});
|
|
136
|
+
verifier.setSigningAlgorithm('HS512');
|
|
137
|
+
|
|
138
|
+
verifier.verify(token, (err, jwt) => {
|
|
139
|
+
if (!err) console.log(jwt.body); // { uid: 1001, iss: ..., exp: ... }
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### 场景三:使用随机密钥(配合 secure-random)
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
const nJwt = require('mm_njwt');
|
|
147
|
+
const secureRandom = require('secure-random');
|
|
148
|
+
|
|
149
|
+
const signingKey = secureRandom(256, { type: 'Buffer' }); // 256 字节随机密钥
|
|
150
|
+
const jwt = nJwt.create({ iss: 'http://myapp.com/', sub: 'users/user1234' }, signingKey);
|
|
151
|
+
console.log(jwt.compact());
|
|
152
|
+
```
|
package/example/index.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* mm_njwt JWT 签发与校验模块示例
|
|
5
|
+
* 演示:创建 JWT、签发 token,并校验签名的有效性。
|
|
6
|
+
* 运行:node example/index.js
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const nJwt = require('../index.js');
|
|
10
|
+
|
|
11
|
+
// 签名密钥(演示用)
|
|
12
|
+
const SECRET = 'my-256-bit-secret-key-0123456789abcdef';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 主函数
|
|
16
|
+
* @returns {void} 无返回值
|
|
17
|
+
*/
|
|
18
|
+
function main() {
|
|
19
|
+
// 1. 创建 JWT 并签发
|
|
20
|
+
const jwt = nJwt.create(
|
|
21
|
+
{ iss: 'http://myapp.com/', sub: 'users/user1234', scope: 'self, admins' },
|
|
22
|
+
SECRET
|
|
23
|
+
);
|
|
24
|
+
const token = jwt.compact();
|
|
25
|
+
console.log('签发的 JWT:', token);
|
|
26
|
+
console.log('载荷:', JSON.stringify(jwt.body.toJSON()));
|
|
27
|
+
|
|
28
|
+
// 2. 校验 JWT
|
|
29
|
+
nJwt.verify(token, SECRET, 'HS256', (err, verified) => {
|
|
30
|
+
if (err) {
|
|
31
|
+
console.error('校验失败:', err.message);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
console.log('校验通过,载荷:', JSON.stringify(verified.body.toJSON()));
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,33 +1,38 @@
|
|
|
1
|
-
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"repository": {
|
|
10
|
-
"type": "git",
|
|
11
|
-
"url": "git+https://gitee.com/qiuwenwu91/mm_njwt.git"
|
|
12
|
-
},
|
|
13
|
-
"keywords": [
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "mm_njwt",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "用于加解密通讯",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node test.js"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://gitee.com/qiuwenwu91/mm_njwt.git"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"mm_mod",
|
|
15
|
+
"mm_infra",
|
|
16
|
+
"mm_signature",
|
|
17
|
+
"wechat",
|
|
18
|
+
"public",
|
|
19
|
+
"bot",
|
|
20
|
+
"robot",
|
|
21
|
+
"encode",
|
|
22
|
+
"decode",
|
|
23
|
+
"njwt"
|
|
24
|
+
],
|
|
25
|
+
"layer": "crosscut",
|
|
26
|
+
"group": "signature",
|
|
27
|
+
"author": "qww",
|
|
28
|
+
"license": "ISC",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://gitee.com/qiuwenwu91/mm_njwt/issues"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://gitee.com/qiuwenwu91/mm_njwt#readme",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"ecdsa-sig-formatter": "^1.0.11",
|
|
35
|
+
"secure-random": "^1.1.2",
|
|
36
|
+
"uuid": "^11.1.0"
|
|
37
|
+
}
|
|
38
|
+
}
|
package/test.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
var nJwt = require('./index.js');
|
|
2
|
-
var secureRandom = require('secure-random');
|
|
3
|
-
|
|
4
|
-
var signingKey = secureRandom(256, {type: 'Buffer'}); // Create a highly random byte array of 256 bytes
|
|
5
|
-
|
|
6
|
-
var claims = {
|
|
7
|
-
iss: "http://myapp.com/", // The URL of your service
|
|
8
|
-
sub: "users/user1234", // The UID of the user in your system
|
|
9
|
-
scope: "self, admins"
|
|
10
|
-
}
|
|
11
|
-
|
|
1
|
+
var nJwt = require('./index.js');
|
|
2
|
+
var secureRandom = require('secure-random');
|
|
3
|
+
|
|
4
|
+
var signingKey = secureRandom(256, {type: 'Buffer'}); // Create a highly random byte array of 256 bytes
|
|
5
|
+
|
|
6
|
+
var claims = {
|
|
7
|
+
iss: "http://myapp.com/", // The URL of your service
|
|
8
|
+
sub: "users/user1234", // The UID of the user in your system
|
|
9
|
+
scope: "self, admins"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
12
|
var jwt = nJwt.create(claims,signingKey);
|
|
13
13
|
console.log(jwt);
|