@lark-apaas/nestjs-authzpaas 0.1.0-alpha.0 → 0.1.0-alpha.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/dist/index.cjs +256 -922
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -349
- package/dist/index.d.ts +52 -349
- package/dist/index.js +241 -900
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -28,169 +28,162 @@ __export(index_exports, {
|
|
|
28
28
|
AuthZPaasGuard: () => AuthZPaasGuard,
|
|
29
29
|
AuthZPaasModule: () => AuthZPaasModule,
|
|
30
30
|
CACHE_CONFIG_TOKEN: () => CACHE_CONFIG_TOKEN,
|
|
31
|
-
CanEnv: () => CanEnv,
|
|
32
|
-
CanPermission: () => CanPermission,
|
|
33
31
|
CanRole: () => CanRole,
|
|
34
32
|
DEFAULT_LOGIN_PATH: () => DEFAULT_LOGIN_PATH,
|
|
35
33
|
ENABLE_MOCK_ROLE_KEY: () => ENABLE_MOCK_ROLE_KEY,
|
|
36
34
|
ENVIRONMENT_KEY: () => ENVIRONMENT_KEY,
|
|
37
35
|
MOCK_ROLES_COOKIE_KEY: () => MOCK_ROLES_COOKIE_KEY,
|
|
38
|
-
|
|
39
|
-
NEED_LOGIN_KEY: () => NEED_LOGIN_KEY,
|
|
36
|
+
NEED_LOGIN_KEY: () => NEED_LOGIN_KEY2,
|
|
40
37
|
PERMISSIONS_KEY: () => PERMISSIONS_KEY,
|
|
41
38
|
PERMISSION_API_CONFIG_TOKEN: () => PERMISSION_API_CONFIG_TOKEN,
|
|
42
|
-
PermissionController: () => PermissionController,
|
|
43
39
|
PermissionDeniedException: () => PermissionDeniedException,
|
|
44
40
|
PermissionDeniedType: () => PermissionDeniedType,
|
|
45
|
-
PermissionDto: () => PermissionDto,
|
|
46
|
-
PermissionResponse: () => PermissionResponse,
|
|
47
41
|
PermissionService: () => PermissionService,
|
|
48
42
|
ROLES_KEY: () => ROLES_KEY,
|
|
49
43
|
ROLE_SUBJECT: () => ROLE_SUBJECT,
|
|
50
|
-
RolesMiddleware: () => RolesMiddleware
|
|
51
|
-
UserId: () => UserId
|
|
44
|
+
RolesMiddleware: () => RolesMiddleware
|
|
52
45
|
});
|
|
53
46
|
module.exports = __toCommonJS(index_exports);
|
|
54
47
|
|
|
55
48
|
// src/authzpaas.module.ts
|
|
56
|
-
var
|
|
57
|
-
var
|
|
58
|
-
|
|
59
|
-
// src/const.ts
|
|
60
|
-
var ANONYMOUS_USER_ID = "anonymous_user_id";
|
|
61
|
-
var PERMISSION_API_CONFIG_TOKEN = Symbol("PERMISSION_API_CONFIG");
|
|
62
|
-
var CACHE_CONFIG_TOKEN = Symbol("CACHE_CONFIG");
|
|
63
|
-
var AUTHZPAAS_MODULE_OPTIONS = Symbol("AUTHZPAAS_MODULE_OPTIONS");
|
|
64
|
-
var ROLES_KEY = "authzpaas:roles";
|
|
65
|
-
var PERMISSIONS_KEY = "authzpaas:permissions";
|
|
66
|
-
var ENVIRONMENT_KEY = "authzpaas:environment";
|
|
67
|
-
var NEED_LOGIN_KEY = "authzpaas:needLogin";
|
|
68
|
-
var DEFAULT_LOGIN_PATH = "/login";
|
|
69
|
-
var MOCK_ROLES_COOKIE_KEY = "mockRoles";
|
|
70
|
-
var ENABLE_MOCK_ROLE_KEY = "__authzpaas_enableMockRole";
|
|
49
|
+
var import_common11 = require("@nestjs/common");
|
|
50
|
+
var import_core4 = require("@nestjs/core");
|
|
71
51
|
|
|
72
52
|
// src/services/permission.service.ts
|
|
73
|
-
var
|
|
53
|
+
var import_common7 = require("@nestjs/common");
|
|
74
54
|
|
|
75
|
-
//
|
|
76
|
-
var
|
|
55
|
+
// ../nestjs-authnpaas/dist/index.js
|
|
56
|
+
var import_common = require("@nestjs/common");
|
|
57
|
+
var import_core = require("@nestjs/core");
|
|
58
|
+
var import_common2 = require("@nestjs/common");
|
|
59
|
+
var import_core2 = require("@nestjs/core");
|
|
60
|
+
var import_common3 = require("@nestjs/common");
|
|
61
|
+
var import_common4 = require("@nestjs/common");
|
|
62
|
+
var __defProp2 = Object.defineProperty;
|
|
63
|
+
var __name2 = /* @__PURE__ */ __name((target, value) => __defProp2(target, "name", {
|
|
64
|
+
value,
|
|
65
|
+
configurable: true
|
|
66
|
+
}), "__name");
|
|
67
|
+
var AUTHNPAAS_MODULE_OPTIONS = Symbol("AUTHNPAAS_MODULE_OPTIONS");
|
|
68
|
+
var NEED_LOGIN_KEY = "authnpaas:needLogin";
|
|
69
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
70
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
71
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
72
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
73
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
74
|
+
}
|
|
75
|
+
__name(_ts_decorate, "_ts_decorate");
|
|
76
|
+
__name2(_ts_decorate, "_ts_decorate");
|
|
77
|
+
function _ts_metadata(k, v) {
|
|
78
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
79
|
+
}
|
|
80
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
81
|
+
__name2(_ts_metadata, "_ts_metadata");
|
|
82
|
+
var AuthNPaasGuard = class {
|
|
77
83
|
static {
|
|
78
|
-
__name(this, "
|
|
84
|
+
__name(this, "AuthNPaasGuard");
|
|
79
85
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
options;
|
|
83
|
-
hits = 0;
|
|
84
|
-
misses = 0;
|
|
85
|
-
constructor(options) {
|
|
86
|
-
this.cache = /* @__PURE__ */ new Map();
|
|
87
|
-
this.accessOrder = [];
|
|
88
|
-
this.options = options;
|
|
86
|
+
static {
|
|
87
|
+
__name2(this, "AuthNPaasGuard");
|
|
89
88
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
get(key) {
|
|
94
|
-
if (!this.options.enabled) {
|
|
95
|
-
return void 0;
|
|
96
|
-
}
|
|
97
|
-
const item = this.cache.get(key);
|
|
98
|
-
if (!item) {
|
|
99
|
-
this.misses++;
|
|
100
|
-
return void 0;
|
|
101
|
-
}
|
|
102
|
-
if (Date.now() > item.expireAt) {
|
|
103
|
-
this.cache.delete(key);
|
|
104
|
-
this.removeFromAccessOrder(key);
|
|
105
|
-
this.misses++;
|
|
106
|
-
return void 0;
|
|
107
|
-
}
|
|
108
|
-
this.updateAccessOrder(key);
|
|
109
|
-
this.hits++;
|
|
110
|
-
return item.value;
|
|
89
|
+
reflector;
|
|
90
|
+
constructor(reflector) {
|
|
91
|
+
this.reflector = reflector;
|
|
111
92
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
93
|
+
async canActivate(context) {
|
|
94
|
+
const http = context.switchToHttp();
|
|
95
|
+
const request = http.getRequest();
|
|
96
|
+
const response = http.getResponse();
|
|
97
|
+
const { userId, loginUrl } = request.userContext || {};
|
|
98
|
+
const needLoginMeta = this.reflector.getAllAndOverride(NEED_LOGIN_KEY, [
|
|
99
|
+
context.getHandler(),
|
|
100
|
+
context.getClass()
|
|
101
|
+
]);
|
|
102
|
+
if (needLoginMeta && !userId && loginUrl) {
|
|
103
|
+
response.redirect(302, loginUrl);
|
|
104
|
+
return false;
|
|
121
105
|
}
|
|
122
|
-
|
|
123
|
-
this.cache.set(key, {
|
|
124
|
-
value,
|
|
125
|
-
expireAt
|
|
126
|
-
});
|
|
127
|
-
this.updateAccessOrder(key);
|
|
106
|
+
return true;
|
|
128
107
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
108
|
+
};
|
|
109
|
+
AuthNPaasGuard = _ts_decorate([
|
|
110
|
+
(0, import_common2.Injectable)(),
|
|
111
|
+
_ts_metadata("design:type", Function),
|
|
112
|
+
_ts_metadata("design:paramtypes", [
|
|
113
|
+
typeof import_core2.Reflector === "undefined" ? Object : import_core2.Reflector
|
|
114
|
+
])
|
|
115
|
+
], AuthNPaasGuard);
|
|
116
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
117
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
118
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
119
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
120
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
121
|
+
}
|
|
122
|
+
__name(_ts_decorate2, "_ts_decorate2");
|
|
123
|
+
__name2(_ts_decorate2, "_ts_decorate");
|
|
124
|
+
var AuthNPaasModule = class _AuthNPaasModule {
|
|
125
|
+
static {
|
|
126
|
+
__name(this, "_AuthNPaasModule");
|
|
135
127
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
*/
|
|
139
|
-
clear() {
|
|
140
|
-
this.cache.clear();
|
|
141
|
-
this.accessOrder = [];
|
|
142
|
-
this.hits = 0;
|
|
143
|
-
this.misses = 0;
|
|
128
|
+
static {
|
|
129
|
+
__name2(this, "AuthNPaasModule");
|
|
144
130
|
}
|
|
145
|
-
|
|
146
|
-
* 获取缓存统计信息
|
|
147
|
-
*/
|
|
148
|
-
getStats() {
|
|
131
|
+
static forRoot(options) {
|
|
149
132
|
return {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
133
|
+
module: _AuthNPaasModule,
|
|
134
|
+
global: true,
|
|
135
|
+
controllers: [],
|
|
136
|
+
providers: [
|
|
137
|
+
// 配置提供者
|
|
138
|
+
{
|
|
139
|
+
provide: AUTHNPAAS_MODULE_OPTIONS,
|
|
140
|
+
useValue: {
|
|
141
|
+
...options || {}
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
// 核心服务
|
|
145
|
+
import_core.Reflector,
|
|
146
|
+
// 服务提供者
|
|
147
|
+
AuthNPaasGuard,
|
|
148
|
+
// 守卫提供者
|
|
149
|
+
{
|
|
150
|
+
provide: import_core.APP_GUARD,
|
|
151
|
+
useClass: AuthNPaasGuard
|
|
152
|
+
}
|
|
153
|
+
],
|
|
154
|
+
exports: []
|
|
155
155
|
};
|
|
156
156
|
}
|
|
157
|
-
/**
|
|
158
|
-
* 更新访问顺序
|
|
159
|
-
*/
|
|
160
|
-
updateAccessOrder(key) {
|
|
161
|
-
this.removeFromAccessOrder(key);
|
|
162
|
-
this.accessOrder.push(key);
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* 从访问顺序中移除
|
|
166
|
-
*/
|
|
167
|
-
removeFromAccessOrder(key) {
|
|
168
|
-
const index = this.accessOrder.indexOf(key);
|
|
169
|
-
if (index > -1) {
|
|
170
|
-
this.accessOrder.splice(index, 1);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* 淘汰最少使用的项
|
|
175
|
-
*/
|
|
176
|
-
evictLRU() {
|
|
177
|
-
if (this.accessOrder.length > 0) {
|
|
178
|
-
const oldestKey = this.accessOrder[0];
|
|
179
|
-
this.delete(oldestKey);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
157
|
};
|
|
158
|
+
AuthNPaasModule = _ts_decorate2([
|
|
159
|
+
(0, import_common.Module)({})
|
|
160
|
+
], AuthNPaasModule);
|
|
161
|
+
var IS_PUBLIC_KEY = "isPublic";
|
|
162
|
+
var Public = /* @__PURE__ */ __name2(() => (0, import_common3.SetMetadata)(IS_PUBLIC_KEY, true), "Public");
|
|
163
|
+
|
|
164
|
+
// src/const.ts
|
|
165
|
+
var ANONYMOUS_USER_ID = "anonymous_user_id";
|
|
166
|
+
var PERMISSION_API_CONFIG_TOKEN = Symbol("PERMISSION_API_CONFIG");
|
|
167
|
+
var CACHE_CONFIG_TOKEN = Symbol("CACHE_CONFIG");
|
|
168
|
+
var AUTHZPAAS_MODULE_OPTIONS = Symbol("AUTHZPAAS_MODULE_OPTIONS");
|
|
169
|
+
var ROLES_KEY = "authzpaas:roles";
|
|
170
|
+
var PERMISSIONS_KEY = "authzpaas:permissions";
|
|
171
|
+
var ENVIRONMENT_KEY = "authzpaas:environment";
|
|
172
|
+
var NEED_LOGIN_KEY2 = "authzpaas:needLogin";
|
|
173
|
+
var DEFAULT_LOGIN_PATH = "/login";
|
|
174
|
+
var MOCK_ROLES_COOKIE_KEY = "mockRoles";
|
|
175
|
+
var ENABLE_MOCK_ROLE_KEY = "__authzpaas_enableMockRole";
|
|
183
176
|
|
|
184
177
|
// src/casl/ability.factory.ts
|
|
185
|
-
var
|
|
178
|
+
var import_common5 = require("@nestjs/common");
|
|
186
179
|
var import_ability = require("@casl/ability");
|
|
187
|
-
function
|
|
180
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
188
181
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
189
182
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
190
183
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
191
184
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
192
185
|
}
|
|
193
|
-
__name(
|
|
186
|
+
__name(_ts_decorate3, "_ts_decorate");
|
|
194
187
|
var ROLE_SUBJECT = "@role";
|
|
195
188
|
var AbilityFactory = class {
|
|
196
189
|
static {
|
|
@@ -201,33 +194,26 @@ var AbilityFactory = class {
|
|
|
201
194
|
*/
|
|
202
195
|
createForUser(permissionData) {
|
|
203
196
|
const { can, build } = new import_ability.AbilityBuilder(import_ability.PureAbility);
|
|
204
|
-
for (const permission of permissionData.permissions) {
|
|
205
|
-
const { sub, actions } = permission;
|
|
206
|
-
for (const action of actions) {
|
|
207
|
-
can(action, sub);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
197
|
for (const role of permissionData.roles) {
|
|
211
198
|
can(role, ROLE_SUBJECT);
|
|
212
199
|
}
|
|
213
200
|
return build();
|
|
214
201
|
}
|
|
215
202
|
};
|
|
216
|
-
AbilityFactory =
|
|
217
|
-
(0,
|
|
203
|
+
AbilityFactory = _ts_decorate3([
|
|
204
|
+
(0, import_common5.Injectable)()
|
|
218
205
|
], AbilityFactory);
|
|
219
206
|
|
|
220
207
|
// src/exceptions/permission-denied.exception.ts
|
|
221
|
-
var
|
|
208
|
+
var import_common6 = require("@nestjs/common");
|
|
222
209
|
var PermissionDeniedType = /* @__PURE__ */ (function(PermissionDeniedType2) {
|
|
223
210
|
PermissionDeniedType2["UNAUTHENTICATED"] = "UNAUTHENTICATED";
|
|
224
211
|
PermissionDeniedType2["ROLE_REQUIRED"] = "ROLE_REQUIRED";
|
|
225
212
|
PermissionDeniedType2["PERMISSION_REQUIRED"] = "PERMISSION_REQUIRED";
|
|
226
|
-
PermissionDeniedType2["ENVIRONMENT_REQUIRED"] = "ENVIRONMENT_REQUIRED";
|
|
227
213
|
PermissionDeniedType2["PERMISSION_CONFIG_QUERY_FAILED"] = "PERMISSION_CONFIG_QUERY_FAILED";
|
|
228
214
|
return PermissionDeniedType2;
|
|
229
215
|
})({});
|
|
230
|
-
var PermissionDeniedException = class _PermissionDeniedException extends
|
|
216
|
+
var PermissionDeniedException = class _PermissionDeniedException extends import_common6.HttpException {
|
|
231
217
|
static {
|
|
232
218
|
__name(this, "PermissionDeniedException");
|
|
233
219
|
}
|
|
@@ -301,30 +287,20 @@ var PermissionDeniedException = class _PermissionDeniedException extends import_
|
|
|
301
287
|
}
|
|
302
288
|
});
|
|
303
289
|
}
|
|
304
|
-
/**
|
|
305
|
-
* 创建环境不满足异常
|
|
306
|
-
*/
|
|
307
|
-
static environmentRequired(requirement, message) {
|
|
308
|
-
return new _PermissionDeniedException({
|
|
309
|
-
type: "ENVIRONMENT_REQUIRED",
|
|
310
|
-
message: message || "\u4E0D\u6EE1\u8DB3\u73AF\u5883\u8981\u6C42",
|
|
311
|
-
environmentRequirement: requirement
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
290
|
};
|
|
315
291
|
|
|
316
292
|
// src/services/permission.service.ts
|
|
317
|
-
function
|
|
293
|
+
function _ts_decorate4(decorators, target, key, desc) {
|
|
318
294
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
319
295
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
320
296
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
321
297
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
322
298
|
}
|
|
323
|
-
__name(
|
|
324
|
-
function
|
|
299
|
+
__name(_ts_decorate4, "_ts_decorate");
|
|
300
|
+
function _ts_metadata2(k, v) {
|
|
325
301
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
326
302
|
}
|
|
327
|
-
__name(
|
|
303
|
+
__name(_ts_metadata2, "_ts_metadata");
|
|
328
304
|
function _ts_param(paramIndex, decorator) {
|
|
329
305
|
return function(target, key) {
|
|
330
306
|
decorator(target, key, paramIndex);
|
|
@@ -337,91 +313,50 @@ var PermissionService = class _PermissionService {
|
|
|
337
313
|
}
|
|
338
314
|
apiConfig;
|
|
339
315
|
abilityFactory;
|
|
340
|
-
logger = new
|
|
341
|
-
|
|
342
|
-
cache;
|
|
343
|
-
// 缓存正在进行中的 Promise,避免重复请求
|
|
344
|
-
pendingRequests = /* @__PURE__ */ new Map();
|
|
345
|
-
constructor(apiConfig, cacheConfig, abilityFactory) {
|
|
316
|
+
logger = new import_common7.Logger(_PermissionService.name);
|
|
317
|
+
constructor(apiConfig, abilityFactory) {
|
|
346
318
|
this.apiConfig = apiConfig;
|
|
347
319
|
this.abilityFactory = abilityFactory;
|
|
348
|
-
this.cache = new MemoryCache({
|
|
349
|
-
ttl: cacheConfig.ttl || 300,
|
|
350
|
-
max: cacheConfig.max || 1e3,
|
|
351
|
-
enabled: cacheConfig.enabled !== false
|
|
352
|
-
});
|
|
353
|
-
this.logger.log(`PermissionService initialized with API: ${apiConfig?.baseUrl}`);
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* 构建权限/Ability 缓存 key
|
|
357
|
-
* - 若存在模拟角色:按角色集合排序拼接 + 用户维度
|
|
358
|
-
* - 否则按 userId/匿名用户
|
|
359
|
-
*/
|
|
360
|
-
buildCacheKey(userId, mockRoles) {
|
|
361
|
-
if (mockRoles && mockRoles.length > 0) {
|
|
362
|
-
const sortedRoles = [
|
|
363
|
-
...mockRoles
|
|
364
|
-
].sort();
|
|
365
|
-
return `@roles:${sortedRoles.join("|")}#u:${userId || ANONYMOUS_USER_ID}`;
|
|
366
|
-
}
|
|
367
|
-
return userId || ANONYMOUS_USER_ID;
|
|
368
320
|
}
|
|
369
321
|
/**
|
|
370
|
-
*
|
|
322
|
+
* 获取用户权限数据
|
|
371
323
|
*/
|
|
372
|
-
async getUserPermissions(
|
|
373
|
-
if (!this.apiConfig?.endpoint) {
|
|
374
|
-
this.logger.warn("Permission API endpoint is not configured, returning null");
|
|
375
|
-
return null;
|
|
376
|
-
}
|
|
377
|
-
const key = this.buildCacheKey(userId, mockRoles);
|
|
378
|
-
const cached = this.cache.get(key);
|
|
379
|
-
if (cached) {
|
|
380
|
-
this.logger.debug(`Cache hit for user ${key}`);
|
|
381
|
-
return cached.permissionData;
|
|
382
|
-
}
|
|
383
|
-
const pendingRequest = this.pendingRequests.get(key);
|
|
384
|
-
if (pendingRequest) {
|
|
385
|
-
this.logger.debug(`Reusing pending request for user ${key}`);
|
|
386
|
-
return pendingRequest;
|
|
387
|
-
}
|
|
388
|
-
this.logger.debug(`Cache miss for key ${key}, fetching from API`);
|
|
324
|
+
async getUserPermissions(requestDto) {
|
|
389
325
|
const requestPromise = (async () => {
|
|
326
|
+
const userId = requestDto.userId || ANONYMOUS_USER_ID;
|
|
390
327
|
try {
|
|
391
|
-
const permissionData =
|
|
328
|
+
const permissionData = await this.fetchFromApi(requestDto);
|
|
392
329
|
const dataWithTimestamp = {
|
|
393
330
|
...permissionData,
|
|
394
331
|
fetchedAt: /* @__PURE__ */ new Date()
|
|
395
332
|
};
|
|
396
|
-
const ability = this.abilityFactory.createForUser(dataWithTimestamp);
|
|
397
|
-
this.cache.set(key, {
|
|
398
|
-
permissionData: dataWithTimestamp,
|
|
399
|
-
ability
|
|
400
|
-
});
|
|
401
333
|
return dataWithTimestamp;
|
|
402
334
|
} catch (error) {
|
|
403
|
-
this.logger.error(`Failed to fetch permissions for
|
|
335
|
+
this.logger.error(`Failed to fetch permissions for user ${userId}:`, error);
|
|
404
336
|
throw error;
|
|
405
|
-
} finally {
|
|
406
|
-
this.pendingRequests.delete(key);
|
|
407
337
|
}
|
|
408
338
|
})();
|
|
409
|
-
this.pendingRequests.set(key, requestPromise);
|
|
410
339
|
return requestPromise;
|
|
411
340
|
}
|
|
412
341
|
/**
|
|
413
342
|
* 从 API 获取权限数据
|
|
414
343
|
* 内置实现,用户无需配置
|
|
415
344
|
*/
|
|
416
|
-
async fetchFromApi(
|
|
417
|
-
const {
|
|
418
|
-
const
|
|
345
|
+
async fetchFromApi(requestDto) {
|
|
346
|
+
const { timeout = 5e3 } = this.apiConfig || {};
|
|
347
|
+
const { baseUrl, userId, appId, cookies, csrfToken } = requestDto;
|
|
348
|
+
const url = `${baseUrl}/api/apps/${appId}/management/permissions/roles`;
|
|
419
349
|
const requestHeaders = {
|
|
420
|
-
"Content-Type": "application/json"
|
|
421
|
-
...headers
|
|
350
|
+
"Content-Type": "application/json"
|
|
422
351
|
};
|
|
423
|
-
if (
|
|
424
|
-
|
|
352
|
+
if (cookies) {
|
|
353
|
+
const cookieString = Object.entries(cookies).map(([key, value]) => `${key}=${value}`).join("; ");
|
|
354
|
+
if (cookieString) {
|
|
355
|
+
requestHeaders.Cookie = cookieString;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (csrfToken) {
|
|
359
|
+
requestHeaders["X-Suda-Csrf-Token"] = csrfToken;
|
|
425
360
|
}
|
|
426
361
|
const controller = new AbortController();
|
|
427
362
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
@@ -438,14 +373,14 @@ var PermissionService = class _PermissionService {
|
|
|
438
373
|
cause: error,
|
|
439
374
|
type: PermissionDeniedType.PERMISSION_CONFIG_QUERY_FAILED,
|
|
440
375
|
message: error.message
|
|
441
|
-
},
|
|
376
|
+
}, import_common7.HttpStatus.INTERNAL_SERVER_ERROR);
|
|
442
377
|
}
|
|
443
378
|
const data = await response.json();
|
|
444
|
-
const roles = (data.roles || []).map((role) => typeof role === "string" ? role : role.name);
|
|
445
379
|
return {
|
|
446
380
|
userId,
|
|
447
|
-
roles,
|
|
448
|
-
|
|
381
|
+
roles: data.role_list || [],
|
|
382
|
+
// TODO: 基于权限点位设置能力
|
|
383
|
+
// permissions: data.permissions || [],
|
|
449
384
|
fetchedAt: /* @__PURE__ */ new Date()
|
|
450
385
|
};
|
|
451
386
|
} catch (error) {
|
|
@@ -458,83 +393,31 @@ var PermissionService = class _PermissionService {
|
|
|
458
393
|
cause: err,
|
|
459
394
|
type: PermissionDeniedType.PERMISSION_CONFIG_QUERY_FAILED,
|
|
460
395
|
message: err.message
|
|
461
|
-
},
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
/**
|
|
465
|
-
*
|
|
466
|
-
*
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
userId,
|
|
487
|
-
roles: data.roles || [],
|
|
488
|
-
permissions: data.permissions || [],
|
|
489
|
-
fetchedAt: /* @__PURE__ */ new Date()
|
|
490
|
-
};
|
|
491
|
-
} catch (error) {
|
|
492
|
-
clearTimeout(timeoutId);
|
|
493
|
-
throw new PermissionDeniedException({
|
|
494
|
-
cause: error,
|
|
495
|
-
type: PermissionDeniedType.PERMISSION_CONFIG_QUERY_FAILED,
|
|
496
|
-
message: error.message
|
|
497
|
-
}, import_common3.HttpStatus.INTERNAL_SERVER_ERROR);
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
/**
|
|
501
|
-
* 获取用户的 Ability 实例(带缓存)
|
|
502
|
-
* @param userId 用户ID
|
|
503
|
-
* @returns CASL Ability 实例
|
|
504
|
-
*/
|
|
505
|
-
async getUserAbility(userId, mockRoles) {
|
|
506
|
-
const key = this.buildCacheKey(userId, mockRoles);
|
|
507
|
-
const cached = this.cache.get(key);
|
|
508
|
-
if (cached) {
|
|
509
|
-
return cached.ability;
|
|
510
|
-
}
|
|
511
|
-
await this.getUserPermissions(userId, mockRoles);
|
|
512
|
-
const newCached = this.cache.get(key);
|
|
513
|
-
return newCached.ability;
|
|
514
|
-
}
|
|
515
|
-
/**
|
|
516
|
-
* 清除用户权限缓存
|
|
517
|
-
*/
|
|
518
|
-
clearUserCache(userId) {
|
|
519
|
-
const key = userId || ANONYMOUS_USER_ID;
|
|
520
|
-
this.cache.delete(key);
|
|
521
|
-
this.pendingRequests.delete(key);
|
|
522
|
-
this.logger.debug(`Cache cleared for user ${key}`);
|
|
523
|
-
}
|
|
524
|
-
/**
|
|
525
|
-
* 清除所有缓存
|
|
526
|
-
*/
|
|
527
|
-
clearAllCache() {
|
|
528
|
-
this.cache.clear();
|
|
529
|
-
this.pendingRequests.clear();
|
|
530
|
-
this.logger.log("All permission cache cleared");
|
|
531
|
-
}
|
|
532
|
-
/**
|
|
533
|
-
* 获取缓存统计信息
|
|
534
|
-
*/
|
|
535
|
-
getCacheStats() {
|
|
536
|
-
return this.cache.getStats();
|
|
537
|
-
}
|
|
396
|
+
}, import_common7.HttpStatus.INTERNAL_SERVER_ERROR);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
// /**
|
|
400
|
+
// * 获取用户的 Ability 实例(带缓存)
|
|
401
|
+
// * @param userId 用户ID
|
|
402
|
+
// * @returns CASL Ability 实例
|
|
403
|
+
// */
|
|
404
|
+
// private async getUserAbility(
|
|
405
|
+
// userId?: string,
|
|
406
|
+
// mockRoles?: string[]
|
|
407
|
+
// ): Promise<AppAbility> {
|
|
408
|
+
// // 计算缓存 key
|
|
409
|
+
// const key = this.buildCacheKey(userId, mockRoles);
|
|
410
|
+
// // 尝试从缓存获取
|
|
411
|
+
// const cached = this.cache.get(key);
|
|
412
|
+
// if (cached) {
|
|
413
|
+
// return cached.ability;
|
|
414
|
+
// }
|
|
415
|
+
// // 缓存未命中,调用 getUserPermissions 会创建并缓存
|
|
416
|
+
// await this.getUserPermissions(userId, mockRoles);
|
|
417
|
+
// // 再次从缓存获取(此时一定存在)
|
|
418
|
+
// const newCached = this.cache.get(key);
|
|
419
|
+
// return newCached!.ability;
|
|
420
|
+
// }
|
|
538
421
|
/**
|
|
539
422
|
* 检查角色要求
|
|
540
423
|
* 使用 CASL Ability 统一鉴权方式
|
|
@@ -543,16 +426,23 @@ var PermissionService = class _PermissionService {
|
|
|
543
426
|
* @returns 用户权限数据
|
|
544
427
|
* @throws PermissionDeniedException 当角色不满足时
|
|
545
428
|
*/
|
|
546
|
-
async checkRoles(requirement,
|
|
547
|
-
const
|
|
429
|
+
async checkRoles(requirement, userContext) {
|
|
430
|
+
const userId = userContext?.userId || ANONYMOUS_USER_ID;
|
|
431
|
+
const permissionData = await this.getUserPermissions({
|
|
432
|
+
baseUrl: userContext?.baseUrl || "",
|
|
433
|
+
userId,
|
|
434
|
+
appId: userContext?.appId || "",
|
|
435
|
+
cookies: userContext?.cookies || {},
|
|
436
|
+
csrfToken: userContext?.csrfToken || ""
|
|
437
|
+
});
|
|
548
438
|
if (!permissionData) {
|
|
549
439
|
throw new PermissionDeniedException({
|
|
550
440
|
cause: new Error("Permission data fetch api is not configured"),
|
|
551
441
|
type: PermissionDeniedType.PERMISSION_CONFIG_QUERY_FAILED,
|
|
552
442
|
message: "Permission data fetch api is not configured"
|
|
553
|
-
},
|
|
443
|
+
}, import_common7.HttpStatus.BAD_REQUEST);
|
|
554
444
|
}
|
|
555
|
-
const ability =
|
|
445
|
+
const ability = this.abilityFactory.createForUser(permissionData);
|
|
556
446
|
const { roles, and } = requirement;
|
|
557
447
|
const checkResults = roles.map((role) => ability.can(role, ROLE_SUBJECT));
|
|
558
448
|
const hasRole = and ? checkResults.every((result) => result) : checkResults.some((result) => result);
|
|
@@ -563,312 +453,117 @@ var PermissionService = class _PermissionService {
|
|
|
563
453
|
}
|
|
564
454
|
return permissionData;
|
|
565
455
|
}
|
|
566
|
-
/**
|
|
567
|
-
* 检查权限要求
|
|
568
|
-
* @param requirements 权限要求列表
|
|
569
|
-
* @param userId 用户ID
|
|
570
|
-
* @returns 用户权限数据
|
|
571
|
-
* @throws PermissionDeniedException 当权限不满足时
|
|
572
|
-
*/
|
|
573
|
-
async checkPermissions(params, userId, mockRoles) {
|
|
574
|
-
const permissionData = await this.getUserPermissions(userId, mockRoles);
|
|
575
|
-
if (!permissionData) {
|
|
576
|
-
throw new PermissionDeniedException({
|
|
577
|
-
cause: new Error("Permission data fetch api is not configured"),
|
|
578
|
-
type: PermissionDeniedType.PERMISSION_CONFIG_QUERY_FAILED,
|
|
579
|
-
message: "Permission data fetch api is not configured"
|
|
580
|
-
}, import_common3.HttpStatus.BAD_REQUEST);
|
|
581
|
-
}
|
|
582
|
-
const { requirements, or } = params;
|
|
583
|
-
if (!requirements || requirements.length === 0) {
|
|
584
|
-
return permissionData;
|
|
585
|
-
}
|
|
586
|
-
const ability = await this.getUserAbility(userId, mockRoles);
|
|
587
|
-
const failedRequirements = [];
|
|
588
|
-
for (const requirement of requirements) {
|
|
589
|
-
const { actions, subject, or: or2 = false } = requirement;
|
|
590
|
-
const checkResults = actions.map((action) => ability.can(action, subject));
|
|
591
|
-
const hasPermission = or2 ? checkResults.some((result) => result) : checkResults.every((result) => result);
|
|
592
|
-
if (!hasPermission) {
|
|
593
|
-
failedRequirements.push({
|
|
594
|
-
actions,
|
|
595
|
-
subject: String(subject),
|
|
596
|
-
or: or2
|
|
597
|
-
});
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
if (failedRequirements.length > 0) {
|
|
601
|
-
if (or && failedRequirements.length === requirements.length) {
|
|
602
|
-
throw PermissionDeniedException.permissionRequired(failedRequirements.map(({ actions, subject }) => ({
|
|
603
|
-
actions,
|
|
604
|
-
subject: String(subject)
|
|
605
|
-
})), true);
|
|
606
|
-
} else if (!or) {
|
|
607
|
-
throw PermissionDeniedException.permissionRequired(failedRequirements.map(({ actions, subject }) => ({
|
|
608
|
-
actions,
|
|
609
|
-
subject: String(subject)
|
|
610
|
-
})), false);
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
return permissionData;
|
|
614
|
-
}
|
|
615
|
-
async getAbility(userId) {
|
|
616
|
-
return this.getUserAbility(userId);
|
|
617
|
-
}
|
|
618
456
|
};
|
|
619
|
-
PermissionService =
|
|
620
|
-
(0,
|
|
621
|
-
|
|
622
|
-
_ts_param(
|
|
623
|
-
|
|
624
|
-
|
|
457
|
+
PermissionService = _ts_decorate4([
|
|
458
|
+
(0, import_common7.Injectable)(),
|
|
459
|
+
Public(),
|
|
460
|
+
_ts_param(0, (0, import_common7.Inject)(PERMISSION_API_CONFIG_TOKEN)),
|
|
461
|
+
_ts_metadata2("design:type", Function),
|
|
462
|
+
_ts_metadata2("design:paramtypes", [
|
|
625
463
|
typeof PermissionApiConfig === "undefined" ? Object : PermissionApiConfig,
|
|
626
|
-
typeof CacheConfig === "undefined" ? Object : CacheConfig,
|
|
627
464
|
typeof AbilityFactory === "undefined" ? Object : AbilityFactory
|
|
628
465
|
])
|
|
629
466
|
], PermissionService);
|
|
630
467
|
|
|
631
468
|
// src/guards/authzpaas.guard.ts
|
|
632
|
-
var
|
|
633
|
-
var
|
|
634
|
-
|
|
635
|
-
// src/utils/index.ts
|
|
636
|
-
function getMockRolesFromCookie(request) {
|
|
637
|
-
const mockRoles = request.cookies?.[MOCK_ROLES_COOKIE_KEY];
|
|
638
|
-
return mockRoles ? mockRoles.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
|
|
639
|
-
}
|
|
640
|
-
__name(getMockRolesFromCookie, "getMockRolesFromCookie");
|
|
641
|
-
|
|
642
|
-
// src/guards/authzpaas.guard.ts
|
|
643
|
-
function _ts_decorate3(decorators, target, key, desc) {
|
|
469
|
+
var import_common8 = require("@nestjs/common");
|
|
470
|
+
var import_core3 = require("@nestjs/core");
|
|
471
|
+
function _ts_decorate5(decorators, target, key, desc) {
|
|
644
472
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
645
473
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
646
474
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
647
475
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
648
476
|
}
|
|
649
|
-
__name(
|
|
650
|
-
function
|
|
477
|
+
__name(_ts_decorate5, "_ts_decorate");
|
|
478
|
+
function _ts_metadata3(k, v) {
|
|
651
479
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
652
480
|
}
|
|
653
|
-
__name(
|
|
654
|
-
function _ts_param2(paramIndex, decorator) {
|
|
655
|
-
return function(target, key) {
|
|
656
|
-
decorator(target, key, paramIndex);
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
__name(_ts_param2, "_ts_param");
|
|
481
|
+
__name(_ts_metadata3, "_ts_metadata");
|
|
660
482
|
var AuthZPaasGuard = class {
|
|
661
483
|
static {
|
|
662
484
|
__name(this, "AuthZPaasGuard");
|
|
663
485
|
}
|
|
664
486
|
reflector;
|
|
665
487
|
permissionService;
|
|
666
|
-
|
|
667
|
-
constructor(reflector, permissionService, moduleOptions) {
|
|
488
|
+
constructor(reflector, permissionService) {
|
|
668
489
|
this.reflector = reflector;
|
|
669
490
|
this.permissionService = permissionService;
|
|
670
|
-
this.moduleOptions = moduleOptions;
|
|
671
491
|
}
|
|
672
492
|
async canActivate(context) {
|
|
673
493
|
const http = context.switchToHttp();
|
|
674
494
|
const request = http.getRequest();
|
|
675
|
-
|
|
676
|
-
const userId = this.extractUserId(request);
|
|
677
|
-
const mockRoles = this.moduleOptions?.enableMockRole ? getMockRolesFromCookie(request) : void 0;
|
|
495
|
+
const userContext = request.userContext;
|
|
678
496
|
const checkRoleRequirement = this.reflector.getAllAndOverride(ROLES_KEY, [
|
|
679
497
|
context.getHandler(),
|
|
680
498
|
context.getClass()
|
|
681
499
|
]);
|
|
682
500
|
if (checkRoleRequirement) {
|
|
683
|
-
await this.checkRoleRequirement(checkRoleRequirement,
|
|
684
|
-
}
|
|
685
|
-
const checkPermissionParams = this.reflector.getAllAndOverride(PERMISSIONS_KEY, [
|
|
686
|
-
context.getHandler(),
|
|
687
|
-
context.getClass()
|
|
688
|
-
]);
|
|
689
|
-
if (checkPermissionParams) {
|
|
690
|
-
await this.checkPermissionRequirement(checkPermissionParams, userId, mockRoles);
|
|
691
|
-
}
|
|
692
|
-
const envRequirement = this.reflector.getAllAndOverride(ENVIRONMENT_KEY, [
|
|
693
|
-
context.getHandler(),
|
|
694
|
-
context.getClass()
|
|
695
|
-
]);
|
|
696
|
-
if (envRequirement) {
|
|
697
|
-
const envContext = this.extractEnvironmentContext(request);
|
|
698
|
-
await this.checkEnvironmentRequirement(envRequirement, envContext, request);
|
|
501
|
+
await this.checkRoleRequirement(checkRoleRequirement, userContext);
|
|
699
502
|
}
|
|
700
503
|
return true;
|
|
701
504
|
}
|
|
702
505
|
/**
|
|
703
|
-
* 从请求中提取用户ID
|
|
704
|
-
* 子类可以重写此方法以适应不同的认证策略
|
|
705
|
-
*/
|
|
706
|
-
extractUserId(request) {
|
|
707
|
-
const mockUserId = request.cookies?.mockUserId;
|
|
708
|
-
if (mockUserId) return mockUserId;
|
|
709
|
-
return request.userContext?.userId;
|
|
710
|
-
}
|
|
711
|
-
/**
|
|
712
|
-
* 从请求中提取环境上下文
|
|
713
|
-
*/
|
|
714
|
-
extractEnvironmentContext(request) {
|
|
715
|
-
const regionHeader = request.headers["x-region"];
|
|
716
|
-
const osHeader = request.headers["x-os"];
|
|
717
|
-
const uaHeader = request.headers["user-agent"];
|
|
718
|
-
const region = Array.isArray(regionHeader) ? regionHeader[0] : regionHeader;
|
|
719
|
-
const os = Array.isArray(osHeader) ? osHeader[0] : osHeader;
|
|
720
|
-
const userAgent = Array.isArray(uaHeader) ? uaHeader[0] : uaHeader;
|
|
721
|
-
return {
|
|
722
|
-
network: {
|
|
723
|
-
ip: request.ip || request.connection?.remoteAddress,
|
|
724
|
-
region
|
|
725
|
-
},
|
|
726
|
-
device: {
|
|
727
|
-
type: this.detectDeviceType(userAgent),
|
|
728
|
-
os,
|
|
729
|
-
browser: userAgent
|
|
730
|
-
},
|
|
731
|
-
custom: {
|
|
732
|
-
headers: request.headers,
|
|
733
|
-
query: request.query
|
|
734
|
-
}
|
|
735
|
-
};
|
|
736
|
-
}
|
|
737
|
-
/**
|
|
738
|
-
* 检测设备类型
|
|
739
|
-
*/
|
|
740
|
-
detectDeviceType(userAgent) {
|
|
741
|
-
if (!userAgent) return "desktop";
|
|
742
|
-
const ua = userAgent.toLowerCase();
|
|
743
|
-
if (/(tablet|ipad|playbook|silk)|(android(?!.*mobile))/i.test(ua)) {
|
|
744
|
-
return "tablet";
|
|
745
|
-
}
|
|
746
|
-
if (/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(ua)) {
|
|
747
|
-
return "mobile";
|
|
748
|
-
}
|
|
749
|
-
return "desktop";
|
|
750
|
-
}
|
|
751
|
-
/**
|
|
752
506
|
* 检查角色要求
|
|
753
507
|
*/
|
|
754
|
-
async checkRoleRequirement(requirement,
|
|
755
|
-
return this.permissionService.checkRoles(requirement,
|
|
756
|
-
}
|
|
757
|
-
/**
|
|
758
|
-
* 检查权限要求
|
|
759
|
-
*/
|
|
760
|
-
async checkPermissionRequirement(params, userId, mockRoles) {
|
|
761
|
-
return this.permissionService.checkPermissions(params, userId, mockRoles);
|
|
762
|
-
}
|
|
763
|
-
/**
|
|
764
|
-
* 检查环境要求
|
|
765
|
-
*/
|
|
766
|
-
async checkEnvironmentRequirement(requirement, envContext, request) {
|
|
767
|
-
if (requirement.network) {
|
|
768
|
-
await this.checkNetworkRequirement(requirement.network, envContext);
|
|
769
|
-
}
|
|
770
|
-
if (requirement.device) {
|
|
771
|
-
await this.checkDeviceRequirement(requirement.device, envContext);
|
|
772
|
-
}
|
|
773
|
-
if (requirement.custom) {
|
|
774
|
-
const result = await requirement.custom(request);
|
|
775
|
-
if (!result) {
|
|
776
|
-
throw PermissionDeniedException.environmentRequired("custom", "\u4E0D\u6EE1\u8DB3\u81EA\u5B9A\u4E49\u73AF\u5883\u8981\u6C42");
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
/**
|
|
781
|
-
* 检查网络要求
|
|
782
|
-
*/
|
|
783
|
-
async checkNetworkRequirement(requirement, envContext) {
|
|
784
|
-
const ip = envContext.network?.ip;
|
|
785
|
-
if (requirement.allowedIPs && ip) {
|
|
786
|
-
const isAllowed = this.checkIPMatch(ip, requirement.allowedIPs);
|
|
787
|
-
if (!isAllowed) {
|
|
788
|
-
throw PermissionDeniedException.environmentRequired("network.allowedIPs", `IP \u5730\u5740\u4E0D\u5728\u5141\u8BB8\u5217\u8868\u4E2D: ${ip}`);
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
if (requirement.blockedIPs && ip) {
|
|
792
|
-
const isBlocked = this.checkIPMatch(ip, requirement.blockedIPs);
|
|
793
|
-
if (isBlocked) {
|
|
794
|
-
throw PermissionDeniedException.environmentRequired("network.blockedIPs", `IP \u5730\u5740\u88AB\u7981\u6B62\u8BBF\u95EE: ${ip}`);
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
if (requirement.allowedRegions && envContext.network?.region) {
|
|
798
|
-
const isAllowed = requirement.allowedRegions.includes(envContext.network.region);
|
|
799
|
-
if (!isAllowed) {
|
|
800
|
-
throw PermissionDeniedException.environmentRequired("network.allowedRegions", `\u5730\u533A\u4E0D\u5728\u5141\u8BB8\u5217\u8868\u4E2D: ${envContext.network.region}`);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
/**
|
|
805
|
-
* 检查设备要求
|
|
806
|
-
*/
|
|
807
|
-
async checkDeviceRequirement(requirement, envContext) {
|
|
808
|
-
if (requirement.types && envContext.device?.type) {
|
|
809
|
-
const isAllowed = requirement.types.includes(envContext.device.type);
|
|
810
|
-
if (!isAllowed) {
|
|
811
|
-
throw PermissionDeniedException.environmentRequired("device.types", `\u4E0D\u5141\u8BB8\u7684\u8BBE\u5907\u7C7B\u578B: ${envContext.device.type}`);
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
/**
|
|
816
|
-
* 检查 IP 是否匹配
|
|
817
|
-
* 简化版本,仅支持精确匹配
|
|
818
|
-
* 生产环境建议使用 ipaddr.js 等库
|
|
819
|
-
*/
|
|
820
|
-
checkIPMatch(ip, patterns) {
|
|
821
|
-
return patterns.some((pattern) => {
|
|
822
|
-
if (pattern === ip) return true;
|
|
823
|
-
return false;
|
|
824
|
-
});
|
|
508
|
+
async checkRoleRequirement(requirement, userContext) {
|
|
509
|
+
return this.permissionService.checkRoles(requirement, userContext);
|
|
825
510
|
}
|
|
826
511
|
};
|
|
827
|
-
AuthZPaasGuard =
|
|
828
|
-
(0,
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
typeof
|
|
833
|
-
typeof PermissionService === "undefined" ? Object : PermissionService,
|
|
834
|
-
typeof AuthZPaasModuleOptions === "undefined" ? Object : AuthZPaasModuleOptions
|
|
512
|
+
AuthZPaasGuard = _ts_decorate5([
|
|
513
|
+
(0, import_common8.Injectable)(),
|
|
514
|
+
_ts_metadata3("design:type", Function),
|
|
515
|
+
_ts_metadata3("design:paramtypes", [
|
|
516
|
+
typeof import_core3.Reflector === "undefined" ? Object : import_core3.Reflector,
|
|
517
|
+
typeof PermissionService === "undefined" ? Object : PermissionService
|
|
835
518
|
])
|
|
836
519
|
], AuthZPaasGuard);
|
|
837
520
|
|
|
838
521
|
// src/middlewares/roles.middleware.ts
|
|
839
|
-
var
|
|
840
|
-
function
|
|
522
|
+
var import_common9 = require("@nestjs/common");
|
|
523
|
+
function _ts_decorate6(decorators, target, key, desc) {
|
|
841
524
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
842
525
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
843
526
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
844
527
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
845
528
|
}
|
|
846
|
-
__name(
|
|
847
|
-
function
|
|
529
|
+
__name(_ts_decorate6, "_ts_decorate");
|
|
530
|
+
function _ts_metadata4(k, v) {
|
|
848
531
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
849
532
|
}
|
|
850
|
-
__name(
|
|
533
|
+
__name(_ts_metadata4, "_ts_metadata");
|
|
851
534
|
var RolesMiddleware = class _RolesMiddleware {
|
|
852
535
|
static {
|
|
853
536
|
__name(this, "RolesMiddleware");
|
|
854
537
|
}
|
|
855
538
|
permissionService;
|
|
856
|
-
logger = new
|
|
539
|
+
logger = new import_common9.Logger(_RolesMiddleware.name);
|
|
857
540
|
constructor(permissionService) {
|
|
858
541
|
this.permissionService = permissionService;
|
|
859
542
|
}
|
|
860
543
|
async use(req, _res, next) {
|
|
861
544
|
try {
|
|
862
|
-
const
|
|
863
|
-
const
|
|
545
|
+
const baseUrl = `${req.protocol}://${req.get("host")}`;
|
|
546
|
+
const userId = req.userContext?.userId ?? "";
|
|
547
|
+
const appId = req.userContext?.appId ?? "";
|
|
548
|
+
const cookies = req.cookies ?? {};
|
|
549
|
+
const csrfToken = req.headers["x-suda-csrf-token"] ?? "";
|
|
864
550
|
this.logger.debug(`Fetching roles for user: ${userId}`);
|
|
865
|
-
const permissionData = await this.permissionService.getUserPermissions(
|
|
551
|
+
const permissionData = await this.permissionService.getUserPermissions({
|
|
552
|
+
baseUrl,
|
|
553
|
+
userId,
|
|
554
|
+
appId,
|
|
555
|
+
cookies,
|
|
556
|
+
csrfToken
|
|
557
|
+
});
|
|
866
558
|
let roles;
|
|
867
559
|
if (permissionData) {
|
|
868
560
|
roles = permissionData.roles;
|
|
869
561
|
}
|
|
562
|
+
req.userContext.baseUrl = baseUrl;
|
|
870
563
|
req.userContext.userRoles = roles;
|
|
871
564
|
req.userContext.userId = userId;
|
|
565
|
+
req.userContext.cookies = cookies;
|
|
566
|
+
req.userContext.csrfToken = csrfToken;
|
|
872
567
|
this.logger.debug(`User ${userId} roles loaded: [${roles?.join(", ")}]`);
|
|
873
568
|
next();
|
|
874
569
|
} catch (error) {
|
|
@@ -877,23 +572,23 @@ var RolesMiddleware = class _RolesMiddleware {
|
|
|
877
572
|
}
|
|
878
573
|
}
|
|
879
574
|
};
|
|
880
|
-
RolesMiddleware =
|
|
881
|
-
(0,
|
|
882
|
-
|
|
883
|
-
|
|
575
|
+
RolesMiddleware = _ts_decorate6([
|
|
576
|
+
(0, import_common9.Injectable)(),
|
|
577
|
+
_ts_metadata4("design:type", Function),
|
|
578
|
+
_ts_metadata4("design:paramtypes", [
|
|
884
579
|
typeof PermissionService === "undefined" ? Object : PermissionService
|
|
885
580
|
])
|
|
886
581
|
], RolesMiddleware);
|
|
887
582
|
|
|
888
583
|
// src/filters/authzpaas-exception.filter.ts
|
|
889
|
-
var
|
|
890
|
-
function
|
|
584
|
+
var import_common10 = require("@nestjs/common");
|
|
585
|
+
function _ts_decorate7(decorators, target, key, desc) {
|
|
891
586
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
892
587
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
893
588
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
894
589
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
895
590
|
}
|
|
896
|
-
__name(
|
|
591
|
+
__name(_ts_decorate7, "_ts_decorate");
|
|
897
592
|
var AuthZPaasExceptionFilter = class {
|
|
898
593
|
static {
|
|
899
594
|
__name(this, "AuthZPaasExceptionFilter");
|
|
@@ -916,60 +611,48 @@ var AuthZPaasExceptionFilter = class {
|
|
|
916
611
|
if (exception.details.requiredPermissions) {
|
|
917
612
|
errorResponse.requiredPermissions = exception.details.requiredPermissions;
|
|
918
613
|
}
|
|
919
|
-
if (exception.details.environmentRequirement) {
|
|
920
|
-
errorResponse.environmentRequirement = exception.details.environmentRequirement;
|
|
921
|
-
}
|
|
922
614
|
if (exception.details.metadata) {
|
|
923
615
|
errorResponse.metadata = exception.details.metadata;
|
|
924
616
|
}
|
|
925
617
|
response.status(status).json(errorResponse);
|
|
926
618
|
}
|
|
927
619
|
};
|
|
928
|
-
AuthZPaasExceptionFilter =
|
|
929
|
-
(0,
|
|
620
|
+
AuthZPaasExceptionFilter = _ts_decorate7([
|
|
621
|
+
(0, import_common10.Catch)(PermissionDeniedException)
|
|
930
622
|
], AuthZPaasExceptionFilter);
|
|
931
623
|
|
|
932
624
|
// src/authzpaas.module.ts
|
|
933
|
-
function
|
|
625
|
+
function _ts_decorate8(decorators, target, key, desc) {
|
|
934
626
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
935
627
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
936
628
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
937
629
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
938
630
|
}
|
|
939
|
-
__name(
|
|
631
|
+
__name(_ts_decorate8, "_ts_decorate");
|
|
940
632
|
var AuthZPaasModule = class _AuthZPaasModule {
|
|
941
633
|
static {
|
|
942
634
|
__name(this, "AuthZPaasModule");
|
|
943
635
|
}
|
|
944
636
|
static forRoot(options) {
|
|
945
|
-
const { permissionApi
|
|
946
|
-
ttl: 300,
|
|
947
|
-
max: 1e3,
|
|
948
|
-
enabled: true
|
|
949
|
-
}, isGlobal = true } = options;
|
|
637
|
+
const { permissionApi } = options;
|
|
950
638
|
return {
|
|
951
639
|
module: _AuthZPaasModule,
|
|
952
|
-
global:
|
|
640
|
+
global: true,
|
|
953
641
|
controllers: [],
|
|
954
642
|
providers: [
|
|
955
643
|
// 配置提供者
|
|
956
644
|
{
|
|
957
645
|
provide: AUTHZPAAS_MODULE_OPTIONS,
|
|
958
646
|
useValue: {
|
|
959
|
-
...options
|
|
960
|
-
loginPath: options.loginPath || DEFAULT_LOGIN_PATH
|
|
647
|
+
...options
|
|
961
648
|
}
|
|
962
649
|
},
|
|
963
650
|
{
|
|
964
651
|
provide: PERMISSION_API_CONFIG_TOKEN,
|
|
965
652
|
useValue: permissionApi
|
|
966
653
|
},
|
|
967
|
-
{
|
|
968
|
-
provide: CACHE_CONFIG_TOKEN,
|
|
969
|
-
useValue: cache
|
|
970
|
-
},
|
|
971
654
|
// 核心服务
|
|
972
|
-
|
|
655
|
+
import_core4.Reflector,
|
|
973
656
|
// 服务提供者
|
|
974
657
|
PermissionService,
|
|
975
658
|
AbilityFactory,
|
|
@@ -977,11 +660,11 @@ var AuthZPaasModule = class _AuthZPaasModule {
|
|
|
977
660
|
RolesMiddleware,
|
|
978
661
|
// 守卫提供者
|
|
979
662
|
{
|
|
980
|
-
provide:
|
|
663
|
+
provide: import_core4.APP_GUARD,
|
|
981
664
|
useClass: AuthZPaasGuard
|
|
982
665
|
},
|
|
983
666
|
{
|
|
984
|
-
provide:
|
|
667
|
+
provide: import_core4.APP_FILTER,
|
|
985
668
|
useClass: AuthZPaasExceptionFilter
|
|
986
669
|
}
|
|
987
670
|
],
|
|
@@ -1023,10 +706,10 @@ var AuthZPaasModule = class _AuthZPaasModule {
|
|
|
1023
706
|
* ```
|
|
1024
707
|
*/
|
|
1025
708
|
static forRootAsync(options) {
|
|
1026
|
-
const { imports = [], inject = [], useFactory
|
|
709
|
+
const { imports = [], inject = [], useFactory } = options;
|
|
1027
710
|
return {
|
|
1028
711
|
module: _AuthZPaasModule,
|
|
1029
|
-
global:
|
|
712
|
+
global: true,
|
|
1030
713
|
imports,
|
|
1031
714
|
controllers: [],
|
|
1032
715
|
providers: [
|
|
@@ -1046,22 +729,8 @@ var AuthZPaasModule = class _AuthZPaasModule {
|
|
|
1046
729
|
AUTHZPAAS_MODULE_OPTIONS
|
|
1047
730
|
]
|
|
1048
731
|
},
|
|
1049
|
-
// 缓存配置提供者
|
|
1050
|
-
{
|
|
1051
|
-
provide: CACHE_CONFIG_TOKEN,
|
|
1052
|
-
useFactory: /* @__PURE__ */ __name((moduleOptions) => {
|
|
1053
|
-
return moduleOptions.cache || {
|
|
1054
|
-
ttl: 300,
|
|
1055
|
-
max: 1e3,
|
|
1056
|
-
enabled: true
|
|
1057
|
-
};
|
|
1058
|
-
}, "useFactory"),
|
|
1059
|
-
inject: [
|
|
1060
|
-
AUTHZPAAS_MODULE_OPTIONS
|
|
1061
|
-
]
|
|
1062
|
-
},
|
|
1063
732
|
// 核心服务
|
|
1064
|
-
|
|
733
|
+
import_core4.Reflector,
|
|
1065
734
|
// 服务提供者
|
|
1066
735
|
PermissionService,
|
|
1067
736
|
AbilityFactory,
|
|
@@ -1069,11 +738,11 @@ var AuthZPaasModule = class _AuthZPaasModule {
|
|
|
1069
738
|
RolesMiddleware,
|
|
1070
739
|
// 守卫提供者
|
|
1071
740
|
{
|
|
1072
|
-
provide:
|
|
741
|
+
provide: import_core4.APP_GUARD,
|
|
1073
742
|
useClass: AuthZPaasGuard
|
|
1074
743
|
},
|
|
1075
744
|
{
|
|
1076
|
-
provide:
|
|
745
|
+
provide: import_core4.APP_FILTER,
|
|
1077
746
|
useClass: AuthZPaasExceptionFilter
|
|
1078
747
|
}
|
|
1079
748
|
],
|
|
@@ -1085,12 +754,12 @@ var AuthZPaasModule = class _AuthZPaasModule {
|
|
|
1085
754
|
};
|
|
1086
755
|
}
|
|
1087
756
|
};
|
|
1088
|
-
AuthZPaasModule =
|
|
1089
|
-
(0,
|
|
757
|
+
AuthZPaasModule = _ts_decorate8([
|
|
758
|
+
(0, import_common11.Module)({})
|
|
1090
759
|
], AuthZPaasModule);
|
|
1091
760
|
|
|
1092
761
|
// src/decorators/can-role.decorator.ts
|
|
1093
|
-
var
|
|
762
|
+
var import_common12 = require("@nestjs/common");
|
|
1094
763
|
var CanRole = /* @__PURE__ */ __name((role, and = false) => {
|
|
1095
764
|
let requirement;
|
|
1096
765
|
if (!Array.isArray(role) && typeof role === "string") {
|
|
@@ -1108,336 +777,8 @@ var CanRole = /* @__PURE__ */ __name((role, and = false) => {
|
|
|
1108
777
|
} else {
|
|
1109
778
|
throw new Error("Invalid CanRole parameter: " + JSON.stringify(role));
|
|
1110
779
|
}
|
|
1111
|
-
return (0,
|
|
780
|
+
return (0, import_common12.SetMetadata)(ROLES_KEY, requirement);
|
|
1112
781
|
}, "CanRole");
|
|
1113
|
-
|
|
1114
|
-
// src/decorators/can-permission.decorator.ts
|
|
1115
|
-
var import_common9 = require("@nestjs/common");
|
|
1116
|
-
var CanPermission = /* @__PURE__ */ __name((permission, or) => {
|
|
1117
|
-
let requirements;
|
|
1118
|
-
if (Array.isArray(permission)) {
|
|
1119
|
-
requirements = permission;
|
|
1120
|
-
} else if (typeof permission === "object" && "subject" in permission) {
|
|
1121
|
-
requirements = [
|
|
1122
|
-
permission
|
|
1123
|
-
];
|
|
1124
|
-
} else {
|
|
1125
|
-
throw new Error("Invalid CanPermission parameter: " + JSON.stringify(permission));
|
|
1126
|
-
}
|
|
1127
|
-
return (0, import_common9.SetMetadata)(PERMISSIONS_KEY, {
|
|
1128
|
-
requirements,
|
|
1129
|
-
or: or ?? false
|
|
1130
|
-
});
|
|
1131
|
-
}, "CanPermission");
|
|
1132
|
-
|
|
1133
|
-
// src/decorators/can-env.decorator.ts
|
|
1134
|
-
var import_common10 = require("@nestjs/common");
|
|
1135
|
-
var CanEnv = /* @__PURE__ */ __name((requirement) => {
|
|
1136
|
-
return (0, import_common10.SetMetadata)(ENVIRONMENT_KEY, requirement);
|
|
1137
|
-
}, "CanEnv");
|
|
1138
|
-
|
|
1139
|
-
// src/decorators/user-id.decorator.ts
|
|
1140
|
-
var import_common11 = require("@nestjs/common");
|
|
1141
|
-
var UserId = (0, import_common11.createParamDecorator)((_data, ctx) => {
|
|
1142
|
-
const request = ctx.switchToHttp().getRequest();
|
|
1143
|
-
return request.userContext?.userId;
|
|
1144
|
-
});
|
|
1145
|
-
|
|
1146
|
-
// src/decorators/mock-roles.decorator.ts
|
|
1147
|
-
var import_common12 = require("@nestjs/common");
|
|
1148
|
-
var MockRoles = (0, import_common12.createParamDecorator)((_data, ctx) => {
|
|
1149
|
-
const request = ctx.switchToHttp().getRequest();
|
|
1150
|
-
const mockRoles = getMockRolesFromCookie(request);
|
|
1151
|
-
return request[ENABLE_MOCK_ROLE_KEY] ? mockRoles : void 0;
|
|
1152
|
-
});
|
|
1153
|
-
|
|
1154
|
-
// src/controllers/permission.controller.ts
|
|
1155
|
-
var import_common13 = require("@nestjs/common");
|
|
1156
|
-
var import_swagger = require("@nestjs/swagger");
|
|
1157
|
-
function _ts_decorate7(decorators, target, key, desc) {
|
|
1158
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1159
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1160
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
1161
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1162
|
-
}
|
|
1163
|
-
__name(_ts_decorate7, "_ts_decorate");
|
|
1164
|
-
function _ts_metadata4(k, v) {
|
|
1165
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1166
|
-
}
|
|
1167
|
-
__name(_ts_metadata4, "_ts_metadata");
|
|
1168
|
-
function _ts_param3(paramIndex, decorator) {
|
|
1169
|
-
return function(target, key) {
|
|
1170
|
-
decorator(target, key, paramIndex);
|
|
1171
|
-
};
|
|
1172
|
-
}
|
|
1173
|
-
__name(_ts_param3, "_ts_param");
|
|
1174
|
-
var PermissionDto = class {
|
|
1175
|
-
static {
|
|
1176
|
-
__name(this, "PermissionDto");
|
|
1177
|
-
}
|
|
1178
|
-
sub;
|
|
1179
|
-
actions;
|
|
1180
|
-
id;
|
|
1181
|
-
name;
|
|
1182
|
-
conditions;
|
|
1183
|
-
};
|
|
1184
|
-
_ts_decorate7([
|
|
1185
|
-
(0, import_swagger.ApiProperty)({
|
|
1186
|
-
description: "\u8D44\u6E90\u7C7B\u578B",
|
|
1187
|
-
example: "task"
|
|
1188
|
-
}),
|
|
1189
|
-
_ts_metadata4("design:type", String)
|
|
1190
|
-
], PermissionDto.prototype, "sub", void 0);
|
|
1191
|
-
_ts_decorate7([
|
|
1192
|
-
(0, import_swagger.ApiProperty)({
|
|
1193
|
-
description: "\u64CD\u4F5C\u7C7B\u578B\u5217\u8868",
|
|
1194
|
-
example: [
|
|
1195
|
-
"create",
|
|
1196
|
-
"read",
|
|
1197
|
-
"update",
|
|
1198
|
-
"delete"
|
|
1199
|
-
],
|
|
1200
|
-
type: [
|
|
1201
|
-
String
|
|
1202
|
-
]
|
|
1203
|
-
}),
|
|
1204
|
-
_ts_metadata4("design:type", Array)
|
|
1205
|
-
], PermissionDto.prototype, "actions", void 0);
|
|
1206
|
-
_ts_decorate7([
|
|
1207
|
-
(0, import_swagger.ApiProperty)({
|
|
1208
|
-
description: "\u6743\u9650ID",
|
|
1209
|
-
required: false
|
|
1210
|
-
}),
|
|
1211
|
-
_ts_metadata4("design:type", String)
|
|
1212
|
-
], PermissionDto.prototype, "id", void 0);
|
|
1213
|
-
_ts_decorate7([
|
|
1214
|
-
(0, import_swagger.ApiProperty)({
|
|
1215
|
-
description: "\u6743\u9650\u540D\u79F0",
|
|
1216
|
-
required: false
|
|
1217
|
-
}),
|
|
1218
|
-
_ts_metadata4("design:type", String)
|
|
1219
|
-
], PermissionDto.prototype, "name", void 0);
|
|
1220
|
-
_ts_decorate7([
|
|
1221
|
-
(0, import_swagger.ApiProperty)({
|
|
1222
|
-
description: "\u6743\u9650\u6761\u4EF6",
|
|
1223
|
-
required: false,
|
|
1224
|
-
type: "object"
|
|
1225
|
-
}),
|
|
1226
|
-
_ts_metadata4("design:type", typeof Record === "undefined" ? Object : Record)
|
|
1227
|
-
], PermissionDto.prototype, "conditions", void 0);
|
|
1228
|
-
var PermissionResponse = class {
|
|
1229
|
-
static {
|
|
1230
|
-
__name(this, "PermissionResponse");
|
|
1231
|
-
}
|
|
1232
|
-
userId;
|
|
1233
|
-
roles;
|
|
1234
|
-
permissions;
|
|
1235
|
-
fetchedAt;
|
|
1236
|
-
};
|
|
1237
|
-
_ts_decorate7([
|
|
1238
|
-
(0, import_swagger.ApiProperty)({
|
|
1239
|
-
description: "\u7528\u6237ID",
|
|
1240
|
-
example: "user123",
|
|
1241
|
-
required: false
|
|
1242
|
-
}),
|
|
1243
|
-
_ts_metadata4("design:type", String)
|
|
1244
|
-
], PermissionResponse.prototype, "userId", void 0);
|
|
1245
|
-
_ts_decorate7([
|
|
1246
|
-
(0, import_swagger.ApiProperty)({
|
|
1247
|
-
description: "\u7528\u6237\u89D2\u8272\u5217\u8868",
|
|
1248
|
-
example: [
|
|
1249
|
-
"admin",
|
|
1250
|
-
"user"
|
|
1251
|
-
],
|
|
1252
|
-
type: [
|
|
1253
|
-
String
|
|
1254
|
-
]
|
|
1255
|
-
}),
|
|
1256
|
-
_ts_metadata4("design:type", Array)
|
|
1257
|
-
], PermissionResponse.prototype, "roles", void 0);
|
|
1258
|
-
_ts_decorate7([
|
|
1259
|
-
(0, import_swagger.ApiProperty)({
|
|
1260
|
-
description: "\u7528\u6237\u6743\u9650\u70B9\u4F4D\u5217\u8868",
|
|
1261
|
-
type: [
|
|
1262
|
-
PermissionDto
|
|
1263
|
-
]
|
|
1264
|
-
}),
|
|
1265
|
-
_ts_metadata4("design:type", Array)
|
|
1266
|
-
], PermissionResponse.prototype, "permissions", void 0);
|
|
1267
|
-
_ts_decorate7([
|
|
1268
|
-
(0, import_swagger.ApiProperty)({
|
|
1269
|
-
description: "\u6570\u636E\u83B7\u53D6\u65F6\u95F4",
|
|
1270
|
-
example: "2025-10-14T00:00:00.000Z"
|
|
1271
|
-
}),
|
|
1272
|
-
_ts_metadata4("design:type", typeof Date === "undefined" ? Object : Date)
|
|
1273
|
-
], PermissionResponse.prototype, "fetchedAt", void 0);
|
|
1274
|
-
var PermissionController = class {
|
|
1275
|
-
static {
|
|
1276
|
-
__name(this, "PermissionController");
|
|
1277
|
-
}
|
|
1278
|
-
permissionService;
|
|
1279
|
-
constructor(permissionService) {
|
|
1280
|
-
this.permissionService = permissionService;
|
|
1281
|
-
}
|
|
1282
|
-
/**
|
|
1283
|
-
* 获取当前用户的权限数据
|
|
1284
|
-
*
|
|
1285
|
-
* @param userId 当前用户ID(从请求上下文中获取)
|
|
1286
|
-
* @returns 用户权限数据
|
|
1287
|
-
*
|
|
1288
|
-
* @example
|
|
1289
|
-
* GET /api/permissions
|
|
1290
|
-
*
|
|
1291
|
-
* Response:
|
|
1292
|
-
* {
|
|
1293
|
-
* "userId": "user123",
|
|
1294
|
-
* "roles": ["admin", "user"],
|
|
1295
|
-
* "permissions": [
|
|
1296
|
-
* { "sub": "task", "actions": ["create", "read", "update", "delete"] }
|
|
1297
|
-
* ],
|
|
1298
|
-
* "fetchedAt": "2025-10-14T00:00:00.000Z"
|
|
1299
|
-
* }
|
|
1300
|
-
*/
|
|
1301
|
-
async getUserPermissions(userId, mockRoles) {
|
|
1302
|
-
const permissionData = await this.permissionService.getUserPermissions(userId, mockRoles);
|
|
1303
|
-
return {
|
|
1304
|
-
userId: permissionData?.userId,
|
|
1305
|
-
roles: permissionData?.roles || [],
|
|
1306
|
-
permissions: permissionData?.permissions || [],
|
|
1307
|
-
fetchedAt: permissionData?.fetchedAt || /* @__PURE__ */ new Date()
|
|
1308
|
-
};
|
|
1309
|
-
}
|
|
1310
|
-
/**
|
|
1311
|
-
* 开启角色模拟:将传入的 userId 写入 cookie,服务端优先使用该值请求权限
|
|
1312
|
-
*/
|
|
1313
|
-
async enableMock(res, roles) {
|
|
1314
|
-
if (!Array.isArray(roles) || roles.length === 0) {
|
|
1315
|
-
return {
|
|
1316
|
-
success: false,
|
|
1317
|
-
message: "roles \u4E0D\u80FD\u4E3A\u7A7A"
|
|
1318
|
-
};
|
|
1319
|
-
}
|
|
1320
|
-
const val = roles.join(",");
|
|
1321
|
-
res.cookie(MOCK_ROLES_COOKIE_KEY, val, {
|
|
1322
|
-
httpOnly: false,
|
|
1323
|
-
sameSite: "lax",
|
|
1324
|
-
maxAge: 24 * 60 * 60 * 1e3,
|
|
1325
|
-
path: "/"
|
|
1326
|
-
});
|
|
1327
|
-
return {
|
|
1328
|
-
success: true,
|
|
1329
|
-
roles
|
|
1330
|
-
};
|
|
1331
|
-
}
|
|
1332
|
-
/**
|
|
1333
|
-
* 关闭角色模拟:清除 cookie
|
|
1334
|
-
*/
|
|
1335
|
-
async disableMock(res) {
|
|
1336
|
-
res.clearCookie(MOCK_ROLES_COOKIE_KEY, {
|
|
1337
|
-
path: "/"
|
|
1338
|
-
});
|
|
1339
|
-
return {
|
|
1340
|
-
success: true
|
|
1341
|
-
};
|
|
1342
|
-
}
|
|
1343
|
-
async getMockRoles(mockRoles, userId) {
|
|
1344
|
-
const permissionData = await this.permissionService.getUserPermissions(userId, mockRoles);
|
|
1345
|
-
return {
|
|
1346
|
-
mocking: !!mockRoles,
|
|
1347
|
-
roles: permissionData?.roles || [],
|
|
1348
|
-
permissions: permissionData?.permissions || [],
|
|
1349
|
-
fetchedAt: permissionData?.fetchedAt || /* @__PURE__ */ new Date(),
|
|
1350
|
-
userId
|
|
1351
|
-
};
|
|
1352
|
-
}
|
|
1353
|
-
};
|
|
1354
|
-
_ts_decorate7([
|
|
1355
|
-
(0, import_common13.Get)(),
|
|
1356
|
-
(0, import_swagger.ApiOperation)({
|
|
1357
|
-
summary: "\u83B7\u53D6\u5F53\u524D\u7528\u6237\u7684\u6743\u9650\u6570\u636E"
|
|
1358
|
-
}),
|
|
1359
|
-
(0, import_swagger.ApiResponse)({
|
|
1360
|
-
status: 200,
|
|
1361
|
-
description: "\u6210\u529F\u8FD4\u56DE\u7528\u6237\u6743\u9650\u6570\u636E",
|
|
1362
|
-
type: PermissionResponse
|
|
1363
|
-
}),
|
|
1364
|
-
(0, import_swagger.ApiResponse)({
|
|
1365
|
-
status: 400,
|
|
1366
|
-
description: "\u7528\u6237\u672A\u8BA4\u8BC1"
|
|
1367
|
-
}),
|
|
1368
|
-
_ts_param3(0, UserId()),
|
|
1369
|
-
_ts_param3(1, MockRoles()),
|
|
1370
|
-
_ts_metadata4("design:type", Function),
|
|
1371
|
-
_ts_metadata4("design:paramtypes", [
|
|
1372
|
-
String,
|
|
1373
|
-
Array
|
|
1374
|
-
]),
|
|
1375
|
-
_ts_metadata4("design:returntype", Promise)
|
|
1376
|
-
], PermissionController.prototype, "getUserPermissions", null);
|
|
1377
|
-
_ts_decorate7([
|
|
1378
|
-
(0, import_common13.Post)("mock/enable"),
|
|
1379
|
-
(0, import_swagger.ApiOperation)({
|
|
1380
|
-
summary: "\u5F00\u542F\u89D2\u8272\u6A21\u62DF\uFF08\u5199\u5165 cookie: mockRoles\uFF09"
|
|
1381
|
-
}),
|
|
1382
|
-
(0, import_swagger.ApiResponse)({
|
|
1383
|
-
status: 200,
|
|
1384
|
-
description: "\u6A21\u62DF\u5DF2\u5F00\u542F"
|
|
1385
|
-
}),
|
|
1386
|
-
_ts_param3(0, (0, import_common13.Res)({
|
|
1387
|
-
passthrough: true
|
|
1388
|
-
})),
|
|
1389
|
-
_ts_param3(1, (0, import_common13.Body)("roles")),
|
|
1390
|
-
_ts_metadata4("design:type", Function),
|
|
1391
|
-
_ts_metadata4("design:paramtypes", [
|
|
1392
|
-
typeof Response === "undefined" ? Object : Response,
|
|
1393
|
-
Array
|
|
1394
|
-
]),
|
|
1395
|
-
_ts_metadata4("design:returntype", Promise)
|
|
1396
|
-
], PermissionController.prototype, "enableMock", null);
|
|
1397
|
-
_ts_decorate7([
|
|
1398
|
-
(0, import_common13.Post)("mock/disable"),
|
|
1399
|
-
(0, import_swagger.ApiOperation)({
|
|
1400
|
-
summary: "\u5173\u95ED\u89D2\u8272\u6A21\u62DF\uFF08\u6E05\u9664 cookie: mockRoles\uFF09"
|
|
1401
|
-
}),
|
|
1402
|
-
(0, import_swagger.ApiResponse)({
|
|
1403
|
-
status: 200,
|
|
1404
|
-
description: "\u6A21\u62DF\u5DF2\u5173\u95ED"
|
|
1405
|
-
}),
|
|
1406
|
-
_ts_param3(0, (0, import_common13.Res)({
|
|
1407
|
-
passthrough: true
|
|
1408
|
-
})),
|
|
1409
|
-
_ts_metadata4("design:type", Function),
|
|
1410
|
-
_ts_metadata4("design:paramtypes", [
|
|
1411
|
-
typeof Response === "undefined" ? Object : Response
|
|
1412
|
-
]),
|
|
1413
|
-
_ts_metadata4("design:returntype", Promise)
|
|
1414
|
-
], PermissionController.prototype, "disableMock", null);
|
|
1415
|
-
_ts_decorate7([
|
|
1416
|
-
(0, import_common13.Get)("mock/status"),
|
|
1417
|
-
(0, import_swagger.ApiOperation)({
|
|
1418
|
-
summary: "\u83B7\u53D6\u5F53\u524D\u7528\u6237\u7684\u89D2\u8272\u6A21\u62DF\u72B6\u6001"
|
|
1419
|
-
}),
|
|
1420
|
-
(0, import_swagger.ApiResponse)({
|
|
1421
|
-
status: 200,
|
|
1422
|
-
description: "\u6210\u529F\u8FD4\u56DE\u89D2\u8272\u6A21\u62DF\u6570\u636E"
|
|
1423
|
-
}),
|
|
1424
|
-
_ts_param3(0, MockRoles()),
|
|
1425
|
-
_ts_param3(1, UserId()),
|
|
1426
|
-
_ts_metadata4("design:type", Function),
|
|
1427
|
-
_ts_metadata4("design:paramtypes", [
|
|
1428
|
-
Object,
|
|
1429
|
-
String
|
|
1430
|
-
]),
|
|
1431
|
-
_ts_metadata4("design:returntype", Promise)
|
|
1432
|
-
], PermissionController.prototype, "getMockRoles", null);
|
|
1433
|
-
PermissionController = _ts_decorate7([
|
|
1434
|
-
(0, import_swagger.ApiTags)("\u6743\u9650\u7BA1\u7406"),
|
|
1435
|
-
(0, import_common13.Controller)("api/permissions"),
|
|
1436
|
-
_ts_metadata4("design:type", Function),
|
|
1437
|
-
_ts_metadata4("design:paramtypes", [
|
|
1438
|
-
typeof PermissionService === "undefined" ? Object : PermissionService
|
|
1439
|
-
])
|
|
1440
|
-
], PermissionController);
|
|
1441
782
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1442
783
|
0 && (module.exports = {
|
|
1443
784
|
ANONYMOUS_USER_ID,
|
|
@@ -1447,26 +788,19 @@ PermissionController = _ts_decorate7([
|
|
|
1447
788
|
AuthZPaasGuard,
|
|
1448
789
|
AuthZPaasModule,
|
|
1449
790
|
CACHE_CONFIG_TOKEN,
|
|
1450
|
-
CanEnv,
|
|
1451
|
-
CanPermission,
|
|
1452
791
|
CanRole,
|
|
1453
792
|
DEFAULT_LOGIN_PATH,
|
|
1454
793
|
ENABLE_MOCK_ROLE_KEY,
|
|
1455
794
|
ENVIRONMENT_KEY,
|
|
1456
795
|
MOCK_ROLES_COOKIE_KEY,
|
|
1457
|
-
MockRoles,
|
|
1458
796
|
NEED_LOGIN_KEY,
|
|
1459
797
|
PERMISSIONS_KEY,
|
|
1460
798
|
PERMISSION_API_CONFIG_TOKEN,
|
|
1461
|
-
PermissionController,
|
|
1462
799
|
PermissionDeniedException,
|
|
1463
800
|
PermissionDeniedType,
|
|
1464
|
-
PermissionDto,
|
|
1465
|
-
PermissionResponse,
|
|
1466
801
|
PermissionService,
|
|
1467
802
|
ROLES_KEY,
|
|
1468
803
|
ROLE_SUBJECT,
|
|
1469
|
-
RolesMiddleware
|
|
1470
|
-
UserId
|
|
804
|
+
RolesMiddleware
|
|
1471
805
|
});
|
|
1472
806
|
//# sourceMappingURL=index.cjs.map
|