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