@pangza/auth 0.0.0-stage → 1.0.1
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 +2 -2
- package/dist/AuthUtil.d.ts +78 -0
- package/dist/AuthUtil.d.ts.map +1 -0
- package/dist/AuthUtil.js +356 -0
- package/dist/AuthUtil.js.map +1 -0
- package/dist/context.d.ts +10 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +15 -0
- package/dist/context.js.map +1 -0
- package/dist/errors.d.ts +19 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +38 -0
- package/dist/errors.js.map +1 -0
- package/dist/flag.d.ts +3 -0
- package/dist/flag.d.ts.map +1 -0
- package/dist/flag.js +7 -0
- package/dist/flag.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +162 -0
- package/dist/index.js.map +1 -0
- package/dist/store.d.ts +72 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +173 -0
- package/dist/store.js.map +1 -0
- package/dist/token.d.ts +16 -0
- package/dist/token.d.ts.map +1 -0
- package/dist/token.js +81 -0
- package/dist/token.js.map +1 -0
- package/dist/types.d.ts +144 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +37 -4
package/dist/index.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.verifyAuthToken = exports.generateStyleToken = exports.createAuthToken = exports.NotRoleError = exports.NotPermissionError = exports.NotLoginError = exports.AuthError = exports.AUTH_MIDDLEWARE_FLAG = exports.isSessionExpired = exports.getAuthOptions = exports.AuthUtil = void 0;
|
|
4
|
+
exports.matchesIgnore = matchesIgnore;
|
|
5
|
+
exports.isGloballyIgnored = isGloballyIgnored;
|
|
6
|
+
exports.default = Auth;
|
|
7
|
+
const context_1 = require("./context");
|
|
8
|
+
const AuthUtil_1 = require("./AuthUtil");
|
|
9
|
+
const flag_1 = require("./flag");
|
|
10
|
+
/** 默认忽略的浏览器/探测路径,避免误进鉴权日志 */
|
|
11
|
+
const DEFAULT_IGNORE_PATHS = [
|
|
12
|
+
"/.well-known",
|
|
13
|
+
"/favicon.ico",
|
|
14
|
+
"/robots.txt",
|
|
15
|
+
"/sitemap.xml",
|
|
16
|
+
];
|
|
17
|
+
function normalizeIgnorePath(p) {
|
|
18
|
+
if (!p)
|
|
19
|
+
return "/";
|
|
20
|
+
let s = p.trim();
|
|
21
|
+
if (!s.startsWith("/"))
|
|
22
|
+
s = `/${s}`;
|
|
23
|
+
// 保留模式里的通配;仅去掉末尾多余 /
|
|
24
|
+
if (s.length > 1 && s.endsWith("/") && !s.endsWith("*/") && !s.endsWith("**/")) {
|
|
25
|
+
s = s.slice(0, -1);
|
|
26
|
+
}
|
|
27
|
+
return s;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* ignore 路径匹配(类 Ant / glob):
|
|
31
|
+
* - `/api/user/login` 精确,或该路径下的子路径
|
|
32
|
+
* - `/api/pub/**` 以 `/api/pub` 开头的全部接口
|
|
33
|
+
* - `/api/pub/*` 仅一层:`/api/pub/xxx`,不含更深
|
|
34
|
+
* - `/api/aes*` 前缀(尾部单个 *)
|
|
35
|
+
*/
|
|
36
|
+
function matchesIgnore(path, ignore = []) {
|
|
37
|
+
const requestPath = normalizeIgnorePath(path);
|
|
38
|
+
const list = [...DEFAULT_IGNORE_PATHS, ...ignore].map(normalizeIgnorePath);
|
|
39
|
+
return list.some((pattern) => matchIgnorePattern(requestPath, pattern));
|
|
40
|
+
}
|
|
41
|
+
function matchIgnorePattern(requestPath, pattern) {
|
|
42
|
+
// /api/pub/** → /api/pub 及其所有子路径
|
|
43
|
+
if (pattern.endsWith("/**")) {
|
|
44
|
+
const base = pattern.slice(0, -3);
|
|
45
|
+
if (!base || base === "/") {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
return requestPath === base || requestPath.startsWith(`${base}/`);
|
|
49
|
+
}
|
|
50
|
+
// /api/pub/* → 仅匹配下一层
|
|
51
|
+
if (pattern.endsWith("/*")) {
|
|
52
|
+
const base = pattern.slice(0, -2);
|
|
53
|
+
if (!requestPath.startsWith(`${base}/`))
|
|
54
|
+
return false;
|
|
55
|
+
const rest = requestPath.slice(base.length + 1);
|
|
56
|
+
return rest.length > 0 && !rest.includes("/");
|
|
57
|
+
}
|
|
58
|
+
// /api/aes* → 尾部单个 * 视为前缀(可跨 /)
|
|
59
|
+
if (pattern.endsWith("*") && !pattern.slice(0, -1).includes("*")) {
|
|
60
|
+
return requestPath.startsWith(pattern.slice(0, -1));
|
|
61
|
+
}
|
|
62
|
+
// 其余含 * / ** 的 glob → 正则
|
|
63
|
+
if (pattern.includes("*")) {
|
|
64
|
+
return globToRegExp(pattern).test(requestPath);
|
|
65
|
+
}
|
|
66
|
+
// 无通配:精确匹配,或「目录前缀」(/api/foo 放行 /api/foo/bar,但不放行 /api/foobar)
|
|
67
|
+
return requestPath === pattern || requestPath.startsWith(`${pattern}/`);
|
|
68
|
+
}
|
|
69
|
+
/** 将 * / ** 转为正则(* 不跨 /,** 跨段) */
|
|
70
|
+
function globToRegExp(pattern) {
|
|
71
|
+
let i = 0;
|
|
72
|
+
let out = "^";
|
|
73
|
+
while (i < pattern.length) {
|
|
74
|
+
const ch = pattern[i];
|
|
75
|
+
if (ch === "*" && pattern[i + 1] === "*") {
|
|
76
|
+
out += ".*";
|
|
77
|
+
i += 2;
|
|
78
|
+
// 吞掉 ** 后紧跟的 /,避免 /**/ 多要求一层
|
|
79
|
+
if (pattern[i] === "/")
|
|
80
|
+
i += 1;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (ch === "*") {
|
|
84
|
+
out += "[^/]*";
|
|
85
|
+
i += 1;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (".+^${}()|[]\\".includes(ch)) {
|
|
89
|
+
out += `\\${ch}`;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
out += ch;
|
|
93
|
+
}
|
|
94
|
+
i += 1;
|
|
95
|
+
}
|
|
96
|
+
out += "/?$";
|
|
97
|
+
return new RegExp(out);
|
|
98
|
+
}
|
|
99
|
+
/** 是否命中 Auth 全局 ignore(优先级最高) */
|
|
100
|
+
function isGloballyIgnored(path) {
|
|
101
|
+
return matchesIgnore(path, (0, AuthUtil_1.getAuthOptions)().ignore ?? []);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Auth 中间件工厂(类 Sa-Token)。
|
|
105
|
+
* 只负责解析 token、注入请求上下文,不强制登录;
|
|
106
|
+
* 需要登录的接口请在业务里调用 AuthUtil.checkLogin()。
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* Auth({
|
|
110
|
+
* tokenName: 'satoken',
|
|
111
|
+
* timeout: 30 * 24 * 60 * 60 * 1000,
|
|
112
|
+
* activityTimeout: -1,
|
|
113
|
+
* allowConcurrentLogin: false,
|
|
114
|
+
* isShare: false,
|
|
115
|
+
* tokenStyle: 'uuid', // 或 'jwt'
|
|
116
|
+
* jwtSecret: 'change-me',
|
|
117
|
+
* })
|
|
118
|
+
*/
|
|
119
|
+
function Auth(options = {}) {
|
|
120
|
+
(0, AuthUtil_1.configureAuth)(options);
|
|
121
|
+
const middleware = (req, _res, next) => {
|
|
122
|
+
// 预检与忽略路径直接放行
|
|
123
|
+
if (req.method === "OPTIONS" || matchesIgnore(req.path, options.ignore)) {
|
|
124
|
+
return next();
|
|
125
|
+
}
|
|
126
|
+
const token = AuthUtil_1.AuthUtil.readTokenFromRequest(req);
|
|
127
|
+
void (async () => {
|
|
128
|
+
try {
|
|
129
|
+
const session = await AuthUtil_1.AuthUtil.loadSession(token, { touch: true });
|
|
130
|
+
context_1.authContext.run({
|
|
131
|
+
req,
|
|
132
|
+
token,
|
|
133
|
+
session,
|
|
134
|
+
}, () => next());
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
next(err);
|
|
138
|
+
}
|
|
139
|
+
})();
|
|
140
|
+
};
|
|
141
|
+
Object.defineProperty(middleware, flag_1.AUTH_MIDDLEWARE_FLAG, {
|
|
142
|
+
value: true,
|
|
143
|
+
enumerable: false,
|
|
144
|
+
});
|
|
145
|
+
return middleware;
|
|
146
|
+
}
|
|
147
|
+
var AuthUtil_2 = require("./AuthUtil");
|
|
148
|
+
Object.defineProperty(exports, "AuthUtil", { enumerable: true, get: function () { return AuthUtil_2.AuthUtil; } });
|
|
149
|
+
Object.defineProperty(exports, "getAuthOptions", { enumerable: true, get: function () { return AuthUtil_2.getAuthOptions; } });
|
|
150
|
+
Object.defineProperty(exports, "isSessionExpired", { enumerable: true, get: function () { return AuthUtil_2.isSessionExpired; } });
|
|
151
|
+
var flag_2 = require("./flag");
|
|
152
|
+
Object.defineProperty(exports, "AUTH_MIDDLEWARE_FLAG", { enumerable: true, get: function () { return flag_2.AUTH_MIDDLEWARE_FLAG; } });
|
|
153
|
+
var errors_1 = require("./errors");
|
|
154
|
+
Object.defineProperty(exports, "AuthError", { enumerable: true, get: function () { return errors_1.AuthError; } });
|
|
155
|
+
Object.defineProperty(exports, "NotLoginError", { enumerable: true, get: function () { return errors_1.NotLoginError; } });
|
|
156
|
+
Object.defineProperty(exports, "NotPermissionError", { enumerable: true, get: function () { return errors_1.NotPermissionError; } });
|
|
157
|
+
Object.defineProperty(exports, "NotRoleError", { enumerable: true, get: function () { return errors_1.NotRoleError; } });
|
|
158
|
+
var token_1 = require("./token");
|
|
159
|
+
Object.defineProperty(exports, "createAuthToken", { enumerable: true, get: function () { return token_1.createAuthToken; } });
|
|
160
|
+
Object.defineProperty(exports, "generateStyleToken", { enumerable: true, get: function () { return token_1.generateStyleToken; } });
|
|
161
|
+
Object.defineProperty(exports, "verifyAuthToken", { enumerable: true, get: function () { return token_1.verifyAuthToken; } });
|
|
162
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { AuthSession, LoginId } from "./types";
|
|
2
|
+
/** 会话存储抽象:内存 / Redis 统一接口 */
|
|
3
|
+
export interface SessionStore {
|
|
4
|
+
set(session: AuthSession): Promise<void>;
|
|
5
|
+
getByToken(token: string): Promise<AuthSession | null>;
|
|
6
|
+
removeByToken(token: string): Promise<void>;
|
|
7
|
+
removeByLoginId(loginId: LoginId): Promise<void>;
|
|
8
|
+
/** 某账号下全部 token */
|
|
9
|
+
listTokensByLoginId(loginId: LoginId): Promise<string[]>;
|
|
10
|
+
/** 刷新活跃时间与 TTL */
|
|
11
|
+
touch(session: AuthSession): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* 内存会话仓库。
|
|
15
|
+
* - tokenMap:token -> 会话
|
|
16
|
+
* - loginIdMap:loginId -> token 集合
|
|
17
|
+
*/
|
|
18
|
+
export declare class MemoryStore implements SessionStore {
|
|
19
|
+
private tokenMap;
|
|
20
|
+
private loginIdMap;
|
|
21
|
+
set(session: AuthSession): Promise<void>;
|
|
22
|
+
getByToken(token: string): Promise<AuthSession | null>;
|
|
23
|
+
removeByToken(token: string): Promise<void>;
|
|
24
|
+
removeByLoginId(loginId: LoginId): Promise<void>;
|
|
25
|
+
listTokensByLoginId(loginId: LoginId): Promise<string[]>;
|
|
26
|
+
touch(session: AuthSession): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
/** Redis 静态方法最小约定(与封装的 Redis 类对齐) */
|
|
29
|
+
export type RedisLike = {
|
|
30
|
+
setJSON(key: string, value: unknown, ttlSeconds?: number): Promise<void>;
|
|
31
|
+
getJSON<T = unknown>(key: string): Promise<T | null>;
|
|
32
|
+
del(...keys: string[]): Promise<number>;
|
|
33
|
+
sAdd(key: string, ...members: string[]): Promise<number>;
|
|
34
|
+
sMembers(key: string): Promise<string[]>;
|
|
35
|
+
sRem(key: string, ...members: string[]): Promise<number>;
|
|
36
|
+
expire?(key: string, ttlSeconds: number): Promise<boolean>;
|
|
37
|
+
/** 剩余秒数;-1 永不过期,-2 不存在 */
|
|
38
|
+
ttl?(key: string): Promise<number>;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Redis 会话仓库(优先使用)。
|
|
42
|
+
* key:
|
|
43
|
+
* - auth:token:{token} -> AuthSession JSON + TTL
|
|
44
|
+
* - auth:uid:{loginId} -> token 集合
|
|
45
|
+
*/
|
|
46
|
+
export declare class RedisStore implements SessionStore {
|
|
47
|
+
private readonly redis;
|
|
48
|
+
constructor(redis: RedisLike);
|
|
49
|
+
private tokenKey;
|
|
50
|
+
private uidKey;
|
|
51
|
+
private ttlSeconds;
|
|
52
|
+
/**
|
|
53
|
+
* uid set 需要过期,否则 token key 过期后 set 残留幽灵 member。
|
|
54
|
+
* 多端登录时只延长、不缩短(取 max(当前剩余, 本次 ttl))。
|
|
55
|
+
*/
|
|
56
|
+
private refreshUidExpire;
|
|
57
|
+
set(session: AuthSession): Promise<void>;
|
|
58
|
+
getByToken(token: string): Promise<AuthSession | null>;
|
|
59
|
+
removeByToken(token: string): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* 清理 uid set 中 token key 已不存在的幽灵 member(TTL 竞态或旧数据)。
|
|
62
|
+
* @returns 仍有效的 token 列表
|
|
63
|
+
*/
|
|
64
|
+
private pruneUidTokens;
|
|
65
|
+
removeByLoginId(loginId: LoginId): Promise<void>;
|
|
66
|
+
listTokensByLoginId(loginId: LoginId): Promise<string[]>;
|
|
67
|
+
touch(session: AuthSession): Promise<void>;
|
|
68
|
+
}
|
|
69
|
+
export declare function getSessionStore(): SessionStore;
|
|
70
|
+
/** 切换会话仓库(配置了 redis 时切到 RedisStore) */
|
|
71
|
+
export declare function setSessionStore(store: SessionStore): void;
|
|
72
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEpD,6BAA6B;AAC7B,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACvD,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjD,mBAAmB;IACnB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACzD,kBAAkB;IAClB,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5C;AAED;;;;GAIG;AACH,qBAAa,WAAY,YAAW,YAAY;IAC9C,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,UAAU,CAAkC;IAE9C,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxC,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAItD,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAY3C,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAUhD,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAKxD,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAGjD;AAED,qCAAqC;AACrC,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzE,OAAO,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACrD,GAAG,CAAC,GAAG,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACzD,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACzC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACzD,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3D,0BAA0B;IAC1B,GAAG,CAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACpC,CAAC;AAEF;;;;;GAKG;AACH,qBAAa,UAAW,YAAW,YAAY;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,SAAS;IAE7C,OAAO,CAAC,QAAQ;IAIhB,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,UAAU;IAQlB;;;OAGG;YACW,gBAAgB;IAcxB,GAAG,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAQxC,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAItD,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQjD;;;OAGG;YACW,cAAc;IAqBtB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAUhD,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAIxD,KAAK,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;CAKjD;AAKD,wBAAgB,eAAe,IAAI,YAAY,CAE9C;AAED,uCAAuC;AACvC,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAEzD"}
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RedisStore = exports.MemoryStore = void 0;
|
|
4
|
+
exports.getSessionStore = getSessionStore;
|
|
5
|
+
exports.setSessionStore = setSessionStore;
|
|
6
|
+
/**
|
|
7
|
+
* 内存会话仓库。
|
|
8
|
+
* - tokenMap:token -> 会话
|
|
9
|
+
* - loginIdMap:loginId -> token 集合
|
|
10
|
+
*/
|
|
11
|
+
class MemoryStore {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.tokenMap = new Map();
|
|
14
|
+
this.loginIdMap = new Map();
|
|
15
|
+
}
|
|
16
|
+
async set(session) {
|
|
17
|
+
this.tokenMap.set(session.token, session);
|
|
18
|
+
const key = String(session.loginId);
|
|
19
|
+
let tokens = this.loginIdMap.get(key);
|
|
20
|
+
if (!tokens) {
|
|
21
|
+
tokens = new Set();
|
|
22
|
+
this.loginIdMap.set(key, tokens);
|
|
23
|
+
}
|
|
24
|
+
tokens.add(session.token);
|
|
25
|
+
}
|
|
26
|
+
async getByToken(token) {
|
|
27
|
+
return this.tokenMap.get(token) ?? null;
|
|
28
|
+
}
|
|
29
|
+
async removeByToken(token) {
|
|
30
|
+
const session = this.tokenMap.get(token);
|
|
31
|
+
if (!session)
|
|
32
|
+
return;
|
|
33
|
+
this.tokenMap.delete(token);
|
|
34
|
+
const key = String(session.loginId);
|
|
35
|
+
const tokens = this.loginIdMap.get(key);
|
|
36
|
+
if (tokens) {
|
|
37
|
+
tokens.delete(token);
|
|
38
|
+
if (tokens.size === 0)
|
|
39
|
+
this.loginIdMap.delete(key);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async removeByLoginId(loginId) {
|
|
43
|
+
const key = String(loginId);
|
|
44
|
+
const tokens = this.loginIdMap.get(key);
|
|
45
|
+
if (!tokens)
|
|
46
|
+
return;
|
|
47
|
+
for (const token of [...tokens]) {
|
|
48
|
+
this.tokenMap.delete(token);
|
|
49
|
+
}
|
|
50
|
+
this.loginIdMap.delete(key);
|
|
51
|
+
}
|
|
52
|
+
async listTokensByLoginId(loginId) {
|
|
53
|
+
const tokens = this.loginIdMap.get(String(loginId));
|
|
54
|
+
return tokens ? [...tokens] : [];
|
|
55
|
+
}
|
|
56
|
+
async touch(session) {
|
|
57
|
+
this.tokenMap.set(session.token, session);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.MemoryStore = MemoryStore;
|
|
61
|
+
/**
|
|
62
|
+
* Redis 会话仓库(优先使用)。
|
|
63
|
+
* key:
|
|
64
|
+
* - auth:token:{token} -> AuthSession JSON + TTL
|
|
65
|
+
* - auth:uid:{loginId} -> token 集合
|
|
66
|
+
*/
|
|
67
|
+
class RedisStore {
|
|
68
|
+
constructor(redis) {
|
|
69
|
+
this.redis = redis;
|
|
70
|
+
}
|
|
71
|
+
tokenKey(token) {
|
|
72
|
+
return `auth:token:${token}`;
|
|
73
|
+
}
|
|
74
|
+
uidKey(loginId) {
|
|
75
|
+
return `auth:uid:${loginId}`;
|
|
76
|
+
}
|
|
77
|
+
ttlSeconds(session) {
|
|
78
|
+
if (session.expireTime >= Number.MAX_SAFE_INTEGER / 2) {
|
|
79
|
+
// 永不过期:不设 TTL(或很长)
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
return Math.max(1, Math.ceil((session.expireTime - Date.now()) / 1000));
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* uid set 需要过期,否则 token key 过期后 set 残留幽灵 member。
|
|
86
|
+
* 多端登录时只延长、不缩短(取 max(当前剩余, 本次 ttl))。
|
|
87
|
+
*/
|
|
88
|
+
async refreshUidExpire(loginId, ttl) {
|
|
89
|
+
if (ttl == null || !this.redis.expire)
|
|
90
|
+
return;
|
|
91
|
+
const key = this.uidKey(loginId);
|
|
92
|
+
if (this.redis.ttl) {
|
|
93
|
+
const left = await this.redis.ttl(key);
|
|
94
|
+
if (left === -1)
|
|
95
|
+
return; // 已是永不过期(永不过期会话)
|
|
96
|
+
if (left > ttl)
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
await this.redis.expire(key, ttl);
|
|
100
|
+
}
|
|
101
|
+
async set(session) {
|
|
102
|
+
const ttl = this.ttlSeconds(session);
|
|
103
|
+
await this.redis.setJSON(this.tokenKey(session.token), session, ttl);
|
|
104
|
+
const uidKey = this.uidKey(session.loginId);
|
|
105
|
+
await this.redis.sAdd(uidKey, session.token);
|
|
106
|
+
await this.refreshUidExpire(session.loginId, ttl);
|
|
107
|
+
}
|
|
108
|
+
async getByToken(token) {
|
|
109
|
+
return this.redis.getJSON(this.tokenKey(token));
|
|
110
|
+
}
|
|
111
|
+
async removeByToken(token) {
|
|
112
|
+
const session = await this.redis.getJSON(this.tokenKey(token));
|
|
113
|
+
await this.redis.del(this.tokenKey(token));
|
|
114
|
+
if (session) {
|
|
115
|
+
await this.redis.sRem(this.uidKey(session.loginId), token);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 清理 uid set 中 token key 已不存在的幽灵 member(TTL 竞态或旧数据)。
|
|
120
|
+
* @returns 仍有效的 token 列表
|
|
121
|
+
*/
|
|
122
|
+
async pruneUidTokens(loginId) {
|
|
123
|
+
const key = this.uidKey(loginId);
|
|
124
|
+
const tokens = await this.redis.sMembers(key);
|
|
125
|
+
if (!tokens.length)
|
|
126
|
+
return [];
|
|
127
|
+
const alive = [];
|
|
128
|
+
const ghosts = [];
|
|
129
|
+
for (const token of tokens) {
|
|
130
|
+
const session = await this.redis.getJSON(this.tokenKey(token));
|
|
131
|
+
if (session)
|
|
132
|
+
alive.push(token);
|
|
133
|
+
else
|
|
134
|
+
ghosts.push(token);
|
|
135
|
+
}
|
|
136
|
+
if (ghosts.length) {
|
|
137
|
+
await this.redis.sRem(key, ...ghosts);
|
|
138
|
+
}
|
|
139
|
+
if (alive.length === 0) {
|
|
140
|
+
await this.redis.del(key);
|
|
141
|
+
}
|
|
142
|
+
return alive;
|
|
143
|
+
}
|
|
144
|
+
async removeByLoginId(loginId) {
|
|
145
|
+
const key = this.uidKey(loginId);
|
|
146
|
+
const tokens = await this.pruneUidTokens(loginId);
|
|
147
|
+
if (tokens.length > 0) {
|
|
148
|
+
await this.redis.del(...tokens.map((t) => this.tokenKey(t)), key);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
await this.redis.del(key);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async listTokensByLoginId(loginId) {
|
|
155
|
+
return this.pruneUidTokens(loginId);
|
|
156
|
+
}
|
|
157
|
+
async touch(session) {
|
|
158
|
+
const ttl = this.ttlSeconds(session);
|
|
159
|
+
await this.redis.setJSON(this.tokenKey(session.token), session, ttl);
|
|
160
|
+
await this.refreshUidExpire(session.loginId, ttl);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
exports.RedisStore = RedisStore;
|
|
164
|
+
/** 当前生效的会话仓库,默认内存 */
|
|
165
|
+
let activeStore = new MemoryStore();
|
|
166
|
+
function getSessionStore() {
|
|
167
|
+
return activeStore;
|
|
168
|
+
}
|
|
169
|
+
/** 切换会话仓库(配置了 redis 时切到 RedisStore) */
|
|
170
|
+
function setSessionStore(store) {
|
|
171
|
+
activeStore = store;
|
|
172
|
+
}
|
|
173
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/dist/token.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { LoginId, ResolvedAuthOptions, TokenStyle } from "./types";
|
|
2
|
+
/** Sa-Token 风格的随机 token 生成 */
|
|
3
|
+
export declare function generateStyleToken(style: TokenStyle): string;
|
|
4
|
+
export interface CreateTokenPayload {
|
|
5
|
+
loginId: LoginId;
|
|
6
|
+
device?: string;
|
|
7
|
+
/** 会话超时 ms;-1 永不过期 */
|
|
8
|
+
timeout: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 按配置生成 token(自定义 createToken > jwt > tokenStyle)。
|
|
12
|
+
*/
|
|
13
|
+
export declare function createAuthToken(options: ResolvedAuthOptions, payload: CreateTokenPayload): Promise<string>;
|
|
14
|
+
/** 校验 JWT 形态 token(非 jwt 风格直接 true) */
|
|
15
|
+
export declare function verifyAuthToken(options: ResolvedAuthOptions, token: string): boolean;
|
|
16
|
+
//# sourceMappingURL=token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAExE,8BAA8B;AAC9B,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAuB5D;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,mBAAmB,EAC5B,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,MAAM,CAAC,CA8BjB;AAED,uCAAuC;AACvC,wBAAgB,eAAe,CAC7B,OAAO,EAAE,mBAAmB,EAC5B,KAAK,EAAE,MAAM,GACZ,OAAO,CAeT"}
|
package/dist/token.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateStyleToken = generateStyleToken;
|
|
7
|
+
exports.createAuthToken = createAuthToken;
|
|
8
|
+
exports.verifyAuthToken = verifyAuthToken;
|
|
9
|
+
const crypto_1 = require("crypto");
|
|
10
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
11
|
+
/** Sa-Token 风格的随机 token 生成 */
|
|
12
|
+
function generateStyleToken(style) {
|
|
13
|
+
switch (style) {
|
|
14
|
+
case "simple-uuid":
|
|
15
|
+
return (0, crypto_1.randomUUID)().replace(/-/g, "");
|
|
16
|
+
case "uuid":
|
|
17
|
+
return (0, crypto_1.randomUUID)();
|
|
18
|
+
case "random-32":
|
|
19
|
+
return (0, crypto_1.randomBytes)(16).toString("hex");
|
|
20
|
+
case "random-64":
|
|
21
|
+
return (0, crypto_1.randomBytes)(32).toString("hex");
|
|
22
|
+
case "random-128":
|
|
23
|
+
return (0, crypto_1.randomBytes)(64).toString("hex");
|
|
24
|
+
case "tik": {
|
|
25
|
+
// 类 Sa-Token tik:短可读风格
|
|
26
|
+
const part = () => (0, crypto_1.randomBytes)(3).toString("hex");
|
|
27
|
+
return `${part()}_${part()}_${part()}`;
|
|
28
|
+
}
|
|
29
|
+
case "jwt":
|
|
30
|
+
// jwt 由 createAuthToken 用密钥签发,这里不应单独走到
|
|
31
|
+
return (0, crypto_1.randomUUID)();
|
|
32
|
+
default:
|
|
33
|
+
return (0, crypto_1.randomUUID)();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 按配置生成 token(自定义 createToken > jwt > tokenStyle)。
|
|
38
|
+
*/
|
|
39
|
+
async function createAuthToken(options, payload) {
|
|
40
|
+
if (options.createToken) {
|
|
41
|
+
return await options.createToken({
|
|
42
|
+
loginId: payload.loginId,
|
|
43
|
+
device: payload.device,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
if (options.tokenStyle === "jwt") {
|
|
47
|
+
const expiresIn = payload.timeout < 0
|
|
48
|
+
? undefined
|
|
49
|
+
: Math.max(1, Math.ceil(payload.timeout / 1000));
|
|
50
|
+
const signOptions = {
|
|
51
|
+
algorithm: (options.jwtAlgorithm || "HS256"),
|
|
52
|
+
};
|
|
53
|
+
if (expiresIn !== undefined) {
|
|
54
|
+
signOptions.expiresIn = expiresIn;
|
|
55
|
+
}
|
|
56
|
+
return jsonwebtoken_1.default.sign({
|
|
57
|
+
loginId: payload.loginId,
|
|
58
|
+
device: payload.device,
|
|
59
|
+
}, options.jwtSecret, signOptions);
|
|
60
|
+
}
|
|
61
|
+
return generateStyleToken(options.tokenStyle);
|
|
62
|
+
}
|
|
63
|
+
/** 校验 JWT 形态 token(非 jwt 风格直接 true) */
|
|
64
|
+
function verifyAuthToken(options, token) {
|
|
65
|
+
if (options.tokenStyle !== "jwt" && !options.createToken) {
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
if (options.tokenStyle !== "jwt") {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
jsonwebtoken_1.default.verify(token, options.jwtSecret, {
|
|
73
|
+
algorithms: [(options.jwtAlgorithm || "HS256")],
|
|
74
|
+
});
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.js","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"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"}
|