@tachybase/module-auth 0.23.48 → 1.0.6
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/dist/client/index.js +5 -5
- package/dist/client/interceptors.d.ts +5 -0
- package/dist/client/locale/index.d.ts +1 -0
- package/dist/client/settings/token-policy/components.d.ts +7 -0
- package/dist/client/settings/token-policy/hooks.d.ts +16 -0
- package/dist/client/settings/token-policy/index.d.ts +1 -0
- package/dist/constants.d.ts +5 -0
- package/dist/constants.js +39 -0
- package/dist/externalVersion.js +12 -9
- package/dist/locale/en-US.json +23 -1
- package/dist/locale/zh-CN.json +22 -1
- package/dist/node_modules/cron/package.json +1 -1
- package/dist/node_modules/ms/index.js +1 -0
- package/dist/node_modules/ms/package.json +1 -0
- package/dist/server/basic-auth.js +3 -3
- package/dist/server/collections/authenticators.js +0 -8
- package/dist/server/collections/issued-tokens.d.ts +2 -0
- package/dist/server/collections/issued-tokens.js +60 -0
- package/dist/server/collections/token-poilcy-config.d.ts +2 -0
- package/dist/server/collections/token-poilcy-config.js +47 -0
- package/dist/server/collections/users-authenticators.js +10 -1
- package/dist/server/locale/en-US.d.ts +1 -0
- package/dist/server/locale/en-US.js +2 -1
- package/dist/server/locale/zh-CN.d.ts +1 -0
- package/dist/server/locale/zh-CN.js +2 -1
- package/dist/server/migrations/20250318163707-create-token-policy.d.ts +6 -0
- package/dist/server/migrations/20250318163707-create-token-policy.js +52 -0
- package/dist/server/plugin.js +136 -27
- package/dist/server/storer.d.ts +8 -2
- package/dist/server/storer.js +26 -3
- package/dist/server/token-controller.d.ts +32 -0
- package/dist/server/token-controller.js +139 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.js +15 -0
- package/package.json +15 -11
|
@@ -36,7 +36,6 @@ var users_authenticators_default = (0, import_database.defineCollection)({
|
|
|
36
36
|
name: "id",
|
|
37
37
|
type: "bigInt",
|
|
38
38
|
autoIncrement: true,
|
|
39
|
-
primaryKey: true,
|
|
40
39
|
allowNull: false
|
|
41
40
|
},
|
|
42
41
|
/**
|
|
@@ -87,6 +86,16 @@ var users_authenticators_default = (0, import_database.defineCollection)({
|
|
|
87
86
|
type: "json",
|
|
88
87
|
name: "meta",
|
|
89
88
|
defaultValue: {}
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
type: "bigInt",
|
|
92
|
+
name: "userId",
|
|
93
|
+
primaryKey: true
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
type: "string",
|
|
97
|
+
name: "authenticator",
|
|
98
|
+
primaryKey: true
|
|
90
99
|
}
|
|
91
100
|
]
|
|
92
101
|
});
|
|
@@ -5,5 +5,6 @@ declare const _default: {
|
|
|
5
5
|
'Not a valid cellphone number, please re-enter': string;
|
|
6
6
|
'The phone number has been registered, please login directly': string;
|
|
7
7
|
'The phone number is not registered, please register first': string;
|
|
8
|
+
'The username, email or password is incorrect, please re-enter': string;
|
|
8
9
|
};
|
|
9
10
|
export default _default;
|
|
@@ -26,5 +26,6 @@ var en_US_default = {
|
|
|
26
26
|
"The password is incorrect, please re-enter": "The password is incorrect, please re-enter",
|
|
27
27
|
"Not a valid cellphone number, please re-enter": "Not a valid cellphone number, please re-enter",
|
|
28
28
|
"The phone number has been registered, please login directly": "The phone number has been registered, please login directly",
|
|
29
|
-
"The phone number is not registered, please register first": "The phone number is not registered, please register first"
|
|
29
|
+
"The phone number is not registered, please register first": "The phone number is not registered, please register first",
|
|
30
|
+
"The username, email or password is incorrect, please re-enter": "The username, email or password is incorrect, please re-enter"
|
|
30
31
|
};
|
|
@@ -7,5 +7,6 @@ declare const _default: {
|
|
|
7
7
|
'Please keep and enable at least one authenticator': string;
|
|
8
8
|
'Please enter your username or email': string;
|
|
9
9
|
'Please enter a valid username': string;
|
|
10
|
+
'The username, email or password is incorrect, please re-enter': string;
|
|
10
11
|
};
|
|
11
12
|
export default _default;
|
|
@@ -28,5 +28,6 @@ var zh_CN_default = {
|
|
|
28
28
|
"The phone number is not registered, please register first": "\u624B\u673A\u53F7\u672A\u6CE8\u518C\uFF0C\u8BF7\u5148\u6CE8\u518C",
|
|
29
29
|
"Please keep and enable at least one authenticator": "\u8BF7\u81F3\u5C11\u4FDD\u7559\u5E76\u542F\u7528\u4E00\u4E2A\u8BA4\u8BC1\u5668",
|
|
30
30
|
"Please enter your username or email": "\u8BF7\u8F93\u5165\u7528\u6237\u540D\u6216\u90AE\u7BB1",
|
|
31
|
-
"Please enter a valid username": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u7528\u6237\u540D"
|
|
31
|
+
"Please enter a valid username": "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u7528\u6237\u540D",
|
|
32
|
+
"The username, email or password is incorrect, please re-enter": "\u7528\u6237\u540D\u90AE\u7BB1\u6216\u8005\u5BC6\u7801\u6709\u8BEF,\u8BF7\u91CD\u65B0\u8F93\u5165"
|
|
32
33
|
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
var create_token_policy_exports = {};
|
|
19
|
+
__export(create_token_policy_exports, {
|
|
20
|
+
default: () => create_token_policy_default
|
|
21
|
+
});
|
|
22
|
+
module.exports = __toCommonJS(create_token_policy_exports);
|
|
23
|
+
var import_server = require("@tachybase/server");
|
|
24
|
+
var import_constants = require("../../constants");
|
|
25
|
+
class create_token_policy_default extends import_server.Migration {
|
|
26
|
+
constructor() {
|
|
27
|
+
super(...arguments);
|
|
28
|
+
this.on = "afterLoad";
|
|
29
|
+
// 'beforeLoad' or 'afterLoad'
|
|
30
|
+
this.appVersion = "<0.23.65";
|
|
31
|
+
}
|
|
32
|
+
async up() {
|
|
33
|
+
const tokenPolicyRepo = this.app.db.getRepository(import_constants.tokenPolicyCollectionName);
|
|
34
|
+
const tokenPolicy = await tokenPolicyRepo.findOne({ filterByTk: import_constants.tokenPolicyRecordKey });
|
|
35
|
+
if (tokenPolicy) {
|
|
36
|
+
this.app.authManager.tokenController.setConfig(tokenPolicy.config);
|
|
37
|
+
} else {
|
|
38
|
+
const config = {
|
|
39
|
+
tokenExpirationTime: "1d",
|
|
40
|
+
sessionExpirationTime: "7d",
|
|
41
|
+
expiredTokenRenewLimit: "1d"
|
|
42
|
+
};
|
|
43
|
+
await tokenPolicyRepo.create({
|
|
44
|
+
values: {
|
|
45
|
+
key: import_constants.tokenPolicyRecordKey,
|
|
46
|
+
config
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
this.app.authManager.tokenController.setConfig(config);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
package/dist/server/plugin.js
CHANGED
|
@@ -31,8 +31,8 @@ __export(plugin_exports, {
|
|
|
31
31
|
default: () => plugin_default
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(plugin_exports);
|
|
34
|
-
var import_path = require("path");
|
|
35
34
|
var import_server = require("@tachybase/server");
|
|
35
|
+
var import_constants = require("../constants");
|
|
36
36
|
var import_preset = require("../preset");
|
|
37
37
|
var import_auth = __toESM(require("./actions/auth"));
|
|
38
38
|
var import_authenticators = __toESM(require("./actions/authenticators"));
|
|
@@ -41,8 +41,29 @@ var import_locale = require("./locale");
|
|
|
41
41
|
var import_authenticator = require("./model/authenticator");
|
|
42
42
|
var import_storer = require("./storer");
|
|
43
43
|
var import_token_blacklist = require("./token-blacklist");
|
|
44
|
+
var import_token_controller = require("./token-controller");
|
|
44
45
|
class PluginAuthServer extends import_server.Plugin {
|
|
45
46
|
afterAdd() {
|
|
47
|
+
this.app.on("afterLoad", async () => {
|
|
48
|
+
if (this.app.authManager.tokenController) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const cache = await this.app.cacheManager.createCache({
|
|
52
|
+
name: "auth-token-controller",
|
|
53
|
+
prefix: "auth-token-controller"
|
|
54
|
+
});
|
|
55
|
+
const tokenController = new import_token_controller.TokenController({ cache, app: this.app, logger: this.app.log });
|
|
56
|
+
this.app.authManager.setTokenControlService(tokenController);
|
|
57
|
+
const tokenPolicyRepo = this.app.db.getRepository(import_constants.tokenPolicyCollectionName);
|
|
58
|
+
try {
|
|
59
|
+
const res = await tokenPolicyRepo.findOne({ filterByTk: import_constants.tokenPolicyRecordKey });
|
|
60
|
+
if (res) {
|
|
61
|
+
this.app.authManager.tokenController.setConfig(res.config);
|
|
62
|
+
}
|
|
63
|
+
} catch (error) {
|
|
64
|
+
this.app.logger.warn("access control config not exist, use default value");
|
|
65
|
+
}
|
|
66
|
+
});
|
|
46
67
|
}
|
|
47
68
|
async beforeLoad() {
|
|
48
69
|
this.app.i18n.addResources("zh-CN", import_preset.namespace, import_locale.zhCN);
|
|
@@ -50,22 +71,16 @@ class PluginAuthServer extends import_server.Plugin {
|
|
|
50
71
|
this.app.db.registerModels({ AuthModel: import_authenticator.AuthModel });
|
|
51
72
|
}
|
|
52
73
|
async load() {
|
|
53
|
-
await this.importCollections((0, import_path.resolve)(__dirname, "collections"));
|
|
54
|
-
this.db.addMigrations({
|
|
55
|
-
namespace: "auth",
|
|
56
|
-
directory: (0, import_path.resolve)(__dirname, "migrations"),
|
|
57
|
-
context: {
|
|
58
|
-
plugin: this
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
74
|
this.cache = await this.app.cacheManager.createCache({
|
|
62
75
|
name: "auth",
|
|
63
76
|
prefix: "auth",
|
|
64
77
|
store: "memory"
|
|
65
78
|
});
|
|
66
79
|
const storer = new import_storer.Storer({
|
|
80
|
+
app: this.app,
|
|
67
81
|
db: this.db,
|
|
68
|
-
cache: this.cache
|
|
82
|
+
cache: this.cache,
|
|
83
|
+
authManager: this.app.authManager
|
|
69
84
|
});
|
|
70
85
|
this.app.authManager.setStorer(storer);
|
|
71
86
|
if (!this.app.authManager.jwt.blacklist) {
|
|
@@ -73,7 +88,33 @@ class PluginAuthServer extends import_server.Plugin {
|
|
|
73
88
|
}
|
|
74
89
|
this.app.authManager.registerTypes(import_preset.presetAuthType, {
|
|
75
90
|
auth: import_basic_auth.BasicAuth,
|
|
76
|
-
title: "Password"
|
|
91
|
+
title: "Password",
|
|
92
|
+
getPublicOptions: (options) => {
|
|
93
|
+
var _a;
|
|
94
|
+
const usersCollection = this.db.getCollection("users");
|
|
95
|
+
let signupForm = ((_a = options == null ? void 0 : options.public) == null ? void 0 : _a.signupForm) || [];
|
|
96
|
+
signupForm = signupForm.filter((item) => item.show);
|
|
97
|
+
if (!(signupForm.length && signupForm.some(
|
|
98
|
+
(item) => ["username", "email"].includes(item.field) && item.show && item.required
|
|
99
|
+
))) {
|
|
100
|
+
signupForm.unshift({ field: "username", show: true, required: true });
|
|
101
|
+
}
|
|
102
|
+
signupForm = signupForm.filter((field) => field.show).map((item) => {
|
|
103
|
+
var _a2;
|
|
104
|
+
const field = usersCollection.getField(item.field);
|
|
105
|
+
return {
|
|
106
|
+
...item,
|
|
107
|
+
uiSchema: {
|
|
108
|
+
...(_a2 = field.options) == null ? void 0 : _a2.uiSchema,
|
|
109
|
+
required: item.required
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
...options == null ? void 0 : options.public,
|
|
115
|
+
signupForm
|
|
116
|
+
};
|
|
117
|
+
}
|
|
77
118
|
});
|
|
78
119
|
Object.entries(import_auth.default).forEach(
|
|
79
120
|
([action, handler]) => {
|
|
@@ -84,10 +125,9 @@ class PluginAuthServer extends import_server.Plugin {
|
|
|
84
125
|
Object.entries(import_authenticators.default).forEach(
|
|
85
126
|
([action, handler]) => this.app.resourcer.registerAction(`authenticators:${action}`, handler)
|
|
86
127
|
);
|
|
87
|
-
["
|
|
88
|
-
["signOut", "changePassword"].forEach((action) => this.app.acl.allow("auth", action, "loggedIn"));
|
|
128
|
+
["signIn", "signUp"].forEach((action) => this.app.acl.allow("auth", action));
|
|
129
|
+
["check", "signOut", "changePassword"].forEach((action) => this.app.acl.allow("auth", action, "loggedIn"));
|
|
89
130
|
this.app.acl.allow("authenticators", "publicList");
|
|
90
|
-
this.app.acl.allow("authenticators", "bindTypes", "loggedIn");
|
|
91
131
|
this.app.acl.registerSnippet({
|
|
92
132
|
name: `pm.${this.name}.authenticators`,
|
|
93
133
|
actions: ["authenticators:*"]
|
|
@@ -100,24 +140,93 @@ class PluginAuthServer extends import_server.Plugin {
|
|
|
100
140
|
const cache = this.app.cache;
|
|
101
141
|
await cache.del(`auth:${user.id}`);
|
|
102
142
|
});
|
|
143
|
+
this.app.on("cache:del:auth", async ({ userId }) => {
|
|
144
|
+
await this.cache.del(`auth:${userId}`);
|
|
145
|
+
});
|
|
146
|
+
this.app.on("ws:message:auth:token", async ({ clientId, payload }) => {
|
|
147
|
+
if (!payload || !payload.token || !payload.authenticator) {
|
|
148
|
+
this.app.emit(`ws:removeTag`, {
|
|
149
|
+
clientId,
|
|
150
|
+
tagKey: "userId"
|
|
151
|
+
});
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const auth = await this.app.authManager.get(payload.authenticator, {
|
|
155
|
+
getBearerToken: () => payload.token,
|
|
156
|
+
app: this.app,
|
|
157
|
+
db: this.app.db,
|
|
158
|
+
cache: this.app.cache,
|
|
159
|
+
logger: this.app.logger,
|
|
160
|
+
log: this.app.log,
|
|
161
|
+
throw: (...args) => {
|
|
162
|
+
throw new Error(...args);
|
|
163
|
+
},
|
|
164
|
+
t: this.app.i18n.t
|
|
165
|
+
});
|
|
166
|
+
let user;
|
|
167
|
+
try {
|
|
168
|
+
user = (await auth.checkToken()).user;
|
|
169
|
+
} catch (error) {
|
|
170
|
+
if (!user) {
|
|
171
|
+
this.app.logger.error(error);
|
|
172
|
+
this.app.emit(`ws:removeTag`, {
|
|
173
|
+
clientId,
|
|
174
|
+
tagKey: "userId"
|
|
175
|
+
});
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
this.app.emit(`ws:setTag`, {
|
|
180
|
+
clientId,
|
|
181
|
+
tagKey: "userId",
|
|
182
|
+
tagValue: user.id
|
|
183
|
+
});
|
|
184
|
+
this.app.emit(`ws:authorized`, {
|
|
185
|
+
clientId,
|
|
186
|
+
userId: user.id
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
this.app.acl.registerSnippet({
|
|
190
|
+
name: `pm.security.token-policy`,
|
|
191
|
+
actions: [`${import_constants.tokenPolicyCollectionName}:*`]
|
|
192
|
+
});
|
|
193
|
+
this.app.db.on(`${import_constants.tokenPolicyCollectionName}.afterSave`, async (model) => {
|
|
194
|
+
var _a;
|
|
195
|
+
(_a = this.app.authManager.tokenController) == null ? void 0 : _a.setConfig(model.config);
|
|
196
|
+
});
|
|
103
197
|
}
|
|
104
198
|
async install(options) {
|
|
105
|
-
const
|
|
106
|
-
const exist = await
|
|
107
|
-
if (exist) {
|
|
199
|
+
const authRepository = this.db.getRepository("authenticators");
|
|
200
|
+
const exist = await authRepository.findOne({ filter: { name: import_preset.presetAuthenticator } });
|
|
201
|
+
if (!exist) {
|
|
202
|
+
await authRepository.create({
|
|
203
|
+
values: {
|
|
204
|
+
name: import_preset.presetAuthenticator,
|
|
205
|
+
authType: import_preset.presetAuthType,
|
|
206
|
+
description: "Sign in with username/email.",
|
|
207
|
+
enabled: true,
|
|
208
|
+
options: {
|
|
209
|
+
public: {
|
|
210
|
+
allowSignUp: true
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
const tokenPolicyRepo = this.app.db.getRepository(import_constants.tokenPolicyCollectionName);
|
|
217
|
+
const res = await tokenPolicyRepo.findOne({ filterByTk: import_constants.tokenPolicyRecordKey });
|
|
218
|
+
if (res) {
|
|
108
219
|
return;
|
|
109
220
|
}
|
|
110
|
-
|
|
221
|
+
const config = {
|
|
222
|
+
tokenExpirationTime: "1d",
|
|
223
|
+
sessionExpirationTime: "7d",
|
|
224
|
+
expiredTokenRenewLimit: "1d"
|
|
225
|
+
};
|
|
226
|
+
await tokenPolicyRepo.create({
|
|
111
227
|
values: {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
description: "Sign in with username/email.",
|
|
115
|
-
enabled: true,
|
|
116
|
-
options: {
|
|
117
|
-
public: {
|
|
118
|
-
allowSignUp: true
|
|
119
|
-
}
|
|
120
|
-
}
|
|
228
|
+
key: import_constants.tokenPolicyRecordKey,
|
|
229
|
+
config
|
|
121
230
|
}
|
|
122
231
|
});
|
|
123
232
|
}
|
package/dist/server/storer.d.ts
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
|
-
import { Storer as IStorer } from '@tachybase/auth';
|
|
1
|
+
import { AuthManager, Storer as IStorer } from '@tachybase/auth';
|
|
2
2
|
import { Cache } from '@tachybase/cache';
|
|
3
3
|
import { Database } from '@tachybase/database';
|
|
4
|
+
import { Application } from '@tachybase/server';
|
|
4
5
|
import { AuthModel } from './model/authenticator';
|
|
5
6
|
export declare class Storer implements IStorer {
|
|
6
7
|
db: Database;
|
|
7
8
|
cache: Cache;
|
|
9
|
+
app: Application;
|
|
10
|
+
authManager: AuthManager;
|
|
8
11
|
key: string;
|
|
9
|
-
constructor({ db, cache }: {
|
|
12
|
+
constructor({ app, db, cache, authManager, }: {
|
|
13
|
+
app?: Application;
|
|
10
14
|
db: Database;
|
|
11
15
|
cache: Cache;
|
|
16
|
+
authManager: AuthManager;
|
|
12
17
|
});
|
|
18
|
+
renderJsonTemplate(authenticator: any): any;
|
|
13
19
|
getCache(): Promise<AuthModel[]>;
|
|
14
20
|
setCache(authenticators: AuthModel[]): Promise<void>;
|
|
15
21
|
get(name: string): Promise<AuthModel>;
|
package/dist/server/storer.js
CHANGED
|
@@ -21,21 +21,43 @@ __export(storer_exports, {
|
|
|
21
21
|
});
|
|
22
22
|
module.exports = __toCommonJS(storer_exports);
|
|
23
23
|
class Storer {
|
|
24
|
-
constructor({
|
|
24
|
+
constructor({
|
|
25
|
+
app,
|
|
26
|
+
db,
|
|
27
|
+
cache,
|
|
28
|
+
authManager
|
|
29
|
+
}) {
|
|
25
30
|
this.key = "authenticators";
|
|
31
|
+
this.app = app;
|
|
26
32
|
this.db = db;
|
|
27
33
|
this.cache = cache;
|
|
34
|
+
this.authManager = authManager;
|
|
28
35
|
this.db.on("authenticators.afterSave", async (model) => {
|
|
29
36
|
if (!model.enabled) {
|
|
30
37
|
await this.cache.delValueInObject(this.key, model.name);
|
|
31
38
|
return;
|
|
32
39
|
}
|
|
33
|
-
await this.cache.setValueInObject(this.key, model.name, model);
|
|
40
|
+
await this.cache.setValueInObject(this.key, model.name, this.renderJsonTemplate(model));
|
|
34
41
|
});
|
|
35
42
|
this.db.on("authenticators.afterDestroy", async (model) => {
|
|
36
43
|
await this.cache.delValueInObject(this.key, model.name);
|
|
37
44
|
});
|
|
38
45
|
}
|
|
46
|
+
renderJsonTemplate(authenticator) {
|
|
47
|
+
var _a, _b;
|
|
48
|
+
if (!authenticator) {
|
|
49
|
+
return authenticator;
|
|
50
|
+
}
|
|
51
|
+
const $env = (_a = this.app) == null ? void 0 : _a.environment;
|
|
52
|
+
if (!$env) {
|
|
53
|
+
return authenticator;
|
|
54
|
+
}
|
|
55
|
+
const config = this.authManager.getAuthConfig(authenticator.authType);
|
|
56
|
+
authenticator.dataValues.options = $env.renderJsonTemplate(authenticator.dataValues.options, {
|
|
57
|
+
omit: (_b = config == null ? void 0 : config.auth) == null ? void 0 : _b["optionsKeysNotAllowedInEnv"]
|
|
58
|
+
});
|
|
59
|
+
return authenticator;
|
|
60
|
+
}
|
|
39
61
|
async getCache() {
|
|
40
62
|
const authenticators = await this.cache.get(this.key);
|
|
41
63
|
if (!authenticators) {
|
|
@@ -45,7 +67,7 @@ class Storer {
|
|
|
45
67
|
}
|
|
46
68
|
async setCache(authenticators) {
|
|
47
69
|
const obj = authenticators.reduce((obj2, authenticator) => {
|
|
48
|
-
obj2[authenticator.name] = authenticator;
|
|
70
|
+
obj2[authenticator.name] = this.renderJsonTemplate(authenticator);
|
|
49
71
|
return obj2;
|
|
50
72
|
}, {});
|
|
51
73
|
await this.cache.set(this.key, obj);
|
|
@@ -56,6 +78,7 @@ class Storer {
|
|
|
56
78
|
const repo = this.db.getRepository("authenticators");
|
|
57
79
|
authenticators = await repo.find({ filter: { enabled: true } });
|
|
58
80
|
await this.setCache(authenticators);
|
|
81
|
+
authenticators = await this.getCache();
|
|
59
82
|
}
|
|
60
83
|
const authenticator = authenticators.find((authenticator2) => authenticator2.name === name);
|
|
61
84
|
return authenticator || authenticators[0];
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ITokenControlService, NumericTokenPolicyConfig, TokenInfo, TokenPolicyConfig } from '@tachybase/auth';
|
|
2
|
+
import { Cache } from '@tachybase/cache';
|
|
3
|
+
import Database from '@tachybase/database';
|
|
4
|
+
import type { SystemLogger } from '@tachybase/logger';
|
|
5
|
+
import Application from '@tachybase/server';
|
|
6
|
+
type TokenControlService = ITokenControlService;
|
|
7
|
+
export declare class TokenController implements TokenControlService {
|
|
8
|
+
cache: Cache;
|
|
9
|
+
app: Application;
|
|
10
|
+
db: Database;
|
|
11
|
+
logger: SystemLogger;
|
|
12
|
+
constructor({ cache, app, logger }: {
|
|
13
|
+
cache: Cache;
|
|
14
|
+
app: Application;
|
|
15
|
+
logger: SystemLogger;
|
|
16
|
+
});
|
|
17
|
+
setTokenInfo(id: string, value: TokenInfo): Promise<void>;
|
|
18
|
+
getConfig(): Promise<NumericTokenPolicyConfig>;
|
|
19
|
+
setConfig(config: TokenPolicyConfig): Promise<void>;
|
|
20
|
+
removeSessionExpiredTokens(userId: number): Promise<any>;
|
|
21
|
+
add({ userId }: {
|
|
22
|
+
userId: number;
|
|
23
|
+
}): Promise<{
|
|
24
|
+
jti: `${string}-${string}-${string}-${string}-${string}`;
|
|
25
|
+
issuedTime: number;
|
|
26
|
+
signInTime: number;
|
|
27
|
+
renewed: boolean;
|
|
28
|
+
userId: number;
|
|
29
|
+
}>;
|
|
30
|
+
renew: TokenControlService['renew'];
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var token_controller_exports = {};
|
|
29
|
+
__export(token_controller_exports, {
|
|
30
|
+
TokenController: () => TokenController
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(token_controller_exports);
|
|
33
|
+
var import_crypto = require("crypto");
|
|
34
|
+
var import_auth = require("@tachybase/auth");
|
|
35
|
+
var import_ms = __toESM(require("ms"));
|
|
36
|
+
var import_constants = require("../constants");
|
|
37
|
+
const JTICACHEKEY = "token-jti";
|
|
38
|
+
class TokenController {
|
|
39
|
+
constructor({ cache, app, logger }) {
|
|
40
|
+
this.renew = async (jti) => {
|
|
41
|
+
const repo = this.app.db.getRepository(import_constants.issuedTokensCollectionName);
|
|
42
|
+
const model = this.app.db.getModel(import_constants.issuedTokensCollectionName);
|
|
43
|
+
const newId = (0, import_crypto.randomUUID)();
|
|
44
|
+
const issuedTime = Date.now();
|
|
45
|
+
const [count] = await model.update(
|
|
46
|
+
{ jti: newId, issuedTime },
|
|
47
|
+
{ where: { jti } }
|
|
48
|
+
);
|
|
49
|
+
if (count === 1) {
|
|
50
|
+
await this.cache.set(`jti-renewed-cahce:${jti}`, { jti: newId, issuedTime }, import_constants.RENEWED_JTI_CACHE_MS);
|
|
51
|
+
this.logger.info("jti renewed", { oldJti: jti, newJti: newId, issuedTime });
|
|
52
|
+
return { jti: newId, issuedTime };
|
|
53
|
+
} else {
|
|
54
|
+
const cachedJtiData = await this.cache.get(`jti-renewed-cahce:${jti}`);
|
|
55
|
+
if (cachedJtiData) {
|
|
56
|
+
return cachedJtiData;
|
|
57
|
+
}
|
|
58
|
+
this.logger.error("jti renew failed", {
|
|
59
|
+
module: "auth",
|
|
60
|
+
submodule: "token-controller",
|
|
61
|
+
method: "renew",
|
|
62
|
+
jti,
|
|
63
|
+
code: import_auth.AuthErrorCode.TOKEN_RENEW_FAILED
|
|
64
|
+
});
|
|
65
|
+
throw new import_auth.AuthError({
|
|
66
|
+
message: "Your session has expired. Please sign in again.",
|
|
67
|
+
code: import_auth.AuthErrorCode.TOKEN_RENEW_FAILED
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
this.cache = cache;
|
|
72
|
+
this.app = app;
|
|
73
|
+
this.logger = logger;
|
|
74
|
+
}
|
|
75
|
+
async setTokenInfo(id, value) {
|
|
76
|
+
const repo = this.app.db.getRepository(import_constants.issuedTokensCollectionName);
|
|
77
|
+
await repo.updateOrCreate({ filterKeys: ["id"], values: value });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
getConfig() {
|
|
81
|
+
return this.cache.wrap("config", async () => {
|
|
82
|
+
const repo = this.app.db.getRepository(import_constants.tokenPolicyCollectionName);
|
|
83
|
+
const configRecord = await repo.findOne({ filterByTk: import_constants.tokenPolicyRecordKey });
|
|
84
|
+
if (!configRecord) return null;
|
|
85
|
+
const config = configRecord.config;
|
|
86
|
+
return {
|
|
87
|
+
tokenExpirationTime: (0, import_ms.default)(config.tokenExpirationTime),
|
|
88
|
+
sessionExpirationTime: (0, import_ms.default)(config.sessionExpirationTime),
|
|
89
|
+
expiredTokenRenewLimit: (0, import_ms.default)(config.expiredTokenRenewLimit)
|
|
90
|
+
};
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
setConfig(config) {
|
|
94
|
+
return this.cache.set("config", {
|
|
95
|
+
tokenExpirationTime: (0, import_ms.default)(config.tokenExpirationTime),
|
|
96
|
+
sessionExpirationTime: (0, import_ms.default)(config.sessionExpirationTime),
|
|
97
|
+
expiredTokenRenewLimit: (0, import_ms.default)(config.expiredTokenRenewLimit)
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
async removeSessionExpiredTokens(userId) {
|
|
101
|
+
const config = await this.getConfig();
|
|
102
|
+
const issuedTokenRepo = this.app.db.getRepository(import_constants.issuedTokensCollectionName);
|
|
103
|
+
const currTS = Date.now();
|
|
104
|
+
return issuedTokenRepo.destroy({
|
|
105
|
+
filter: {
|
|
106
|
+
userId,
|
|
107
|
+
signInTime: {
|
|
108
|
+
$lt: currTS - config.sessionExpirationTime
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
async add({ userId }) {
|
|
114
|
+
const jti = (0, import_crypto.randomUUID)();
|
|
115
|
+
const currTS = Date.now();
|
|
116
|
+
const data = {
|
|
117
|
+
jti,
|
|
118
|
+
issuedTime: currTS,
|
|
119
|
+
signInTime: currTS,
|
|
120
|
+
renewed: false,
|
|
121
|
+
userId
|
|
122
|
+
};
|
|
123
|
+
await this.setTokenInfo(jti, data);
|
|
124
|
+
try {
|
|
125
|
+
if (process.env.DB_DIALECT === "sqlite") {
|
|
126
|
+
await this.removeSessionExpiredTokens(userId);
|
|
127
|
+
} else {
|
|
128
|
+
this.removeSessionExpiredTokens(userId);
|
|
129
|
+
}
|
|
130
|
+
} catch (err) {
|
|
131
|
+
this.logger.error(err, { module: "auth", submodule: "token-controller", method: "removeSessionExpiredTokens" });
|
|
132
|
+
}
|
|
133
|
+
return data;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
137
|
+
0 && (module.exports = {
|
|
138
|
+
TokenController
|
|
139
|
+
});
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type { TokenPolicyConfig as TokenPolicyConfig } from '@tachybase/auth';
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __copyProps = (to, from, except, desc) => {
|
|
6
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
7
|
+
for (let key of __getOwnPropNames(from))
|
|
8
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
9
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
10
|
+
}
|
|
11
|
+
return to;
|
|
12
|
+
};
|
|
13
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
14
|
+
var types_exports = {};
|
|
15
|
+
module.exports = __toCommonJS(types_exports);
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tachybase/module-auth",
|
|
3
3
|
"displayName": "Authentication",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "1.0.6",
|
|
5
5
|
"description": "User authentication management, including password, SMS, and support for Single Sign-On (SSO) protocols, with extensibility.",
|
|
6
6
|
"keywords": [
|
|
7
|
-
"Authentication"
|
|
7
|
+
"Authentication",
|
|
8
|
+
"Security"
|
|
8
9
|
],
|
|
9
10
|
"main": "./dist/server/index.js",
|
|
10
11
|
"dependencies": {},
|
|
@@ -12,20 +13,23 @@
|
|
|
12
13
|
"@ant-design/icons": "~5.3.7",
|
|
13
14
|
"antd": "5.22.5",
|
|
14
15
|
"cron": "^3.3.1",
|
|
16
|
+
"lodash": "^4.17.21",
|
|
17
|
+
"ms": "^2.1.3",
|
|
15
18
|
"react": "^18.3.1",
|
|
16
19
|
"react-i18next": "^15.2.0",
|
|
17
20
|
"react-router-dom": "6.28.1",
|
|
18
|
-
"@tachybase/schema": "0.
|
|
21
|
+
"@tachybase/schema": "1.0.6"
|
|
19
22
|
},
|
|
20
23
|
"peerDependencies": {
|
|
21
|
-
"@tachybase/actions": "0.
|
|
22
|
-
"@tachybase/auth": "0.
|
|
23
|
-
"@tachybase/client": "0.
|
|
24
|
-
"@tachybase/
|
|
25
|
-
"@tachybase/
|
|
26
|
-
"@tachybase/
|
|
27
|
-
"@tachybase/
|
|
28
|
-
"@tachybase/
|
|
24
|
+
"@tachybase/actions": "1.0.6",
|
|
25
|
+
"@tachybase/auth": "1.0.6",
|
|
26
|
+
"@tachybase/client": "1.0.6",
|
|
27
|
+
"@tachybase/server": "1.0.6",
|
|
28
|
+
"@tachybase/cache": "1.0.6",
|
|
29
|
+
"@tachybase/logger": "1.0.6",
|
|
30
|
+
"@tachybase/database": "1.0.6",
|
|
31
|
+
"@tachybase/test": "1.0.6",
|
|
32
|
+
"@tachybase/utils": "1.0.6"
|
|
29
33
|
},
|
|
30
34
|
"description.zh-CN": "用户认证管理,包括基础的密码认证、短信认证、SSO 协议的认证等,可扩展。",
|
|
31
35
|
"displayName.zh-CN": "用户认证",
|