@yelon/acl 15.1.2 → 15.2.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/LICENSE +21 -21
- package/README.md +23 -23
- package/esm2020/acl.mjs +4 -4
- package/esm2020/index.mjs +7 -7
- package/esm2020/src/acl-guard.mjs +57 -57
- package/esm2020/src/acl-if.directive.mjs +78 -78
- package/esm2020/src/acl.config.mjs +3 -3
- package/esm2020/src/acl.directive.mjs +47 -47
- package/esm2020/src/acl.module.mjs +26 -26
- package/esm2020/src/acl.service.mjs +194 -194
- package/esm2020/src/acl.type.mjs +6 -6
- package/fesm2015/acl.mjs +395 -395
- package/fesm2015/acl.mjs.map +1 -1
- package/fesm2020/acl.mjs +405 -405
- package/fesm2020/acl.mjs.map +1 -1
- package/index.d.ts +7 -7
- package/package.json +51 -51
- package/src/acl-guard.d.ts +28 -28
- package/src/acl-if.directive.d.ts +26 -26
- package/src/acl.config.d.ts +2 -2
- package/src/acl.directive.d.ts +18 -18
- package/src/acl.module.d.ts +11 -11
- package/src/acl.service.d.ts +78 -78
- package/src/acl.type.d.ts +32 -32
- package/src/style/index.less +7 -7
package/fesm2015/acl.mjs
CHANGED
|
@@ -1,395 +1,395 @@
|
|
|
1
|
-
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, Directive, Input, NgModule } from '@angular/core';
|
|
3
|
-
import { BehaviorSubject, filter, Observable, of, map, tap } from 'rxjs';
|
|
4
|
-
import * as i1 from '@yelon/util/config';
|
|
5
|
-
import * as i2 from '@angular/router';
|
|
6
|
-
import { CommonModule } from '@angular/common';
|
|
7
|
-
|
|
8
|
-
const ACL_DEFAULT_CONFIG = {
|
|
9
|
-
guard_url: `/403`
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* ACL 控制服务,[在线文档](https://ng.yunzainfo.com/acl)
|
|
14
|
-
*
|
|
15
|
-
* 务必在根目录注册 `YelonACLModule.forRoot()` 才能使用服务
|
|
16
|
-
*/
|
|
17
|
-
class ACLService {
|
|
18
|
-
/** ACL变更通知 */
|
|
19
|
-
get change() {
|
|
20
|
-
return this.aclChange.asObservable();
|
|
21
|
-
}
|
|
22
|
-
/** 获取所有数据 */
|
|
23
|
-
get data() {
|
|
24
|
-
return {
|
|
25
|
-
full: this.full,
|
|
26
|
-
roles: this.roles,
|
|
27
|
-
abilities: this.abilities
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
get guard_url() {
|
|
31
|
-
return this.options.guard_url;
|
|
32
|
-
}
|
|
33
|
-
constructor(configSrv) {
|
|
34
|
-
this.roles = [];
|
|
35
|
-
this.abilities = [];
|
|
36
|
-
this.full = false;
|
|
37
|
-
this.aclChange = new BehaviorSubject(null);
|
|
38
|
-
this.options = configSrv.merge('acl', ACL_DEFAULT_CONFIG);
|
|
39
|
-
}
|
|
40
|
-
parseACLType(val) {
|
|
41
|
-
let t;
|
|
42
|
-
if (typeof val === 'number') {
|
|
43
|
-
t = { ability: [val] };
|
|
44
|
-
}
|
|
45
|
-
else if (Array.isArray(val) && val.length > 0 && typeof val[0] === 'number') {
|
|
46
|
-
t = { ability: val };
|
|
47
|
-
}
|
|
48
|
-
else if (typeof val === 'object' && !Array.isArray(val)) {
|
|
49
|
-
t = Object.assign({}, val);
|
|
50
|
-
}
|
|
51
|
-
else if (Array.isArray(val)) {
|
|
52
|
-
t = { role: val };
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
t = { role: val == null ? [] : [val] };
|
|
56
|
-
}
|
|
57
|
-
return Object.assign({ except: false }, t);
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* 设置当前用户角色或权限能力(会先清除所有)
|
|
61
|
-
*/
|
|
62
|
-
set(value) {
|
|
63
|
-
this.full = false;
|
|
64
|
-
this.abilities = [];
|
|
65
|
-
this.roles = [];
|
|
66
|
-
this.add(value);
|
|
67
|
-
this.aclChange.next(value);
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* 标识当前用户为全量,即不受限
|
|
71
|
-
*/
|
|
72
|
-
setFull(val) {
|
|
73
|
-
this.full = val;
|
|
74
|
-
this.aclChange.next(val);
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* 设置当前用户权限能力(会先清除所有)
|
|
78
|
-
*/
|
|
79
|
-
setAbility(abilities) {
|
|
80
|
-
this.set({ ability: abilities });
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* 设置当前用户角色(会先清除所有)
|
|
84
|
-
*/
|
|
85
|
-
setRole(roles) {
|
|
86
|
-
this.set({ role: roles });
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* 为当前用户增加角色或权限能力
|
|
90
|
-
*/
|
|
91
|
-
add(value) {
|
|
92
|
-
if (value.role && value.role.length > 0) {
|
|
93
|
-
this.roles.push(...value.role);
|
|
94
|
-
}
|
|
95
|
-
if (value.ability && value.ability.length > 0) {
|
|
96
|
-
this.abilities.push(...value.ability);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* 为当前用户附加角色
|
|
101
|
-
*/
|
|
102
|
-
attachRole(roles) {
|
|
103
|
-
for (const val of roles) {
|
|
104
|
-
if (!this.roles.includes(val)) {
|
|
105
|
-
this.roles.push(val);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
this.aclChange.next(this.data);
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* 为当前用户附加权限
|
|
112
|
-
*/
|
|
113
|
-
attachAbility(abilities) {
|
|
114
|
-
for (const val of abilities) {
|
|
115
|
-
if (!this.abilities.includes(val)) {
|
|
116
|
-
this.abilities.push(val);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
this.aclChange.next(this.data);
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* 为当前用户移除角色
|
|
123
|
-
*/
|
|
124
|
-
removeRole(roles) {
|
|
125
|
-
for (const val of roles) {
|
|
126
|
-
const idx = this.roles.indexOf(val);
|
|
127
|
-
if (idx !== -1) {
|
|
128
|
-
this.roles.splice(idx, 1);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
this.aclChange.next(this.data);
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* 为当前用户移除权限
|
|
135
|
-
*/
|
|
136
|
-
removeAbility(abilities) {
|
|
137
|
-
for (const val of abilities) {
|
|
138
|
-
const idx = this.abilities.indexOf(val);
|
|
139
|
-
if (idx !== -1) {
|
|
140
|
-
this.abilities.splice(idx, 1);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
this.aclChange.next(this.data);
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* 当前用户是否有对应角色,其实 `number` 表示Ability
|
|
147
|
-
*
|
|
148
|
-
* - 当 `full: true` 或参数 `null` 时返回 `true`
|
|
149
|
-
* - 若使用 `ACLType` 参数,可以指定 `mode` 校验模式
|
|
150
|
-
*/
|
|
151
|
-
can(roleOrAbility) {
|
|
152
|
-
const { preCan } = this.options;
|
|
153
|
-
if (preCan) {
|
|
154
|
-
roleOrAbility = preCan(roleOrAbility);
|
|
155
|
-
}
|
|
156
|
-
const t = this.parseACLType(roleOrAbility);
|
|
157
|
-
let result = false;
|
|
158
|
-
if (this.full === true || !roleOrAbility) {
|
|
159
|
-
result = true;
|
|
160
|
-
}
|
|
161
|
-
else {
|
|
162
|
-
if (t.role && t.role.length > 0) {
|
|
163
|
-
if (t.mode === 'allOf') {
|
|
164
|
-
result = t.role.every(v => this.roles.includes(v));
|
|
165
|
-
}
|
|
166
|
-
else {
|
|
167
|
-
result = t.role.some(v => this.roles.includes(v));
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
if (t.ability && t.ability.length > 0) {
|
|
171
|
-
if (t.mode === 'allOf') {
|
|
172
|
-
result = t.ability.every(v => this.abilities.includes(v));
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
result = t.ability.some(v => this.abilities.includes(v));
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
return t.except === true ? !result : result;
|
|
180
|
-
}
|
|
181
|
-
/** @inner */
|
|
182
|
-
parseAbility(value) {
|
|
183
|
-
if (typeof value === 'number' || typeof value === 'string' || Array.isArray(value)) {
|
|
184
|
-
value = { ability: Array.isArray(value) ? value : [value] };
|
|
185
|
-
}
|
|
186
|
-
delete value.role;
|
|
187
|
-
return value;
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* 当前用户是否有对应权限点
|
|
191
|
-
*/
|
|
192
|
-
canAbility(value) {
|
|
193
|
-
return this.can(this.parseAbility(value));
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
ACLService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.
|
|
197
|
-
ACLService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.
|
|
198
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.
|
|
199
|
-
type: Injectable
|
|
200
|
-
}], ctorParameters: function () { return [{ type: i1.YunzaiConfigService }]; } });
|
|
201
|
-
|
|
202
|
-
class ACLIfDirective {
|
|
203
|
-
constructor(templateRef, srv, _viewContainer) {
|
|
204
|
-
this.srv = srv;
|
|
205
|
-
this._viewContainer = _viewContainer;
|
|
206
|
-
this._thenTemplateRef = null;
|
|
207
|
-
this._elseTemplateRef = null;
|
|
208
|
-
this._thenViewRef = null;
|
|
209
|
-
this._elseViewRef = null;
|
|
210
|
-
this._except = false;
|
|
211
|
-
this._change$ = this.srv.change.pipe(filter(r => r != null)).subscribe(() => this._updateView());
|
|
212
|
-
this._thenTemplateRef = templateRef;
|
|
213
|
-
}
|
|
214
|
-
set aclIf(value) {
|
|
215
|
-
this._value = value;
|
|
216
|
-
this._updateView();
|
|
217
|
-
}
|
|
218
|
-
set aclIfThen(templateRef) {
|
|
219
|
-
this._thenTemplateRef = templateRef;
|
|
220
|
-
this._thenViewRef = null;
|
|
221
|
-
this._updateView();
|
|
222
|
-
}
|
|
223
|
-
set aclIfElse(templateRef) {
|
|
224
|
-
this._elseTemplateRef = templateRef;
|
|
225
|
-
this._elseViewRef = null;
|
|
226
|
-
this._updateView();
|
|
227
|
-
}
|
|
228
|
-
set except(value) {
|
|
229
|
-
this._except = value != null && `${value}` !== 'false';
|
|
230
|
-
}
|
|
231
|
-
get except() {
|
|
232
|
-
return this._except;
|
|
233
|
-
}
|
|
234
|
-
_updateView() {
|
|
235
|
-
const res = this.srv.can(this._value);
|
|
236
|
-
if ((res && !this.except) || (!res && this.except)) {
|
|
237
|
-
if (!this._thenViewRef) {
|
|
238
|
-
this._viewContainer.clear();
|
|
239
|
-
this._elseViewRef = null;
|
|
240
|
-
if (this._thenTemplateRef) {
|
|
241
|
-
this._thenViewRef = this._viewContainer.createEmbeddedView(this._thenTemplateRef);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
else {
|
|
246
|
-
if (!this._elseViewRef) {
|
|
247
|
-
this._viewContainer.clear();
|
|
248
|
-
this._thenViewRef = null;
|
|
249
|
-
if (this._elseTemplateRef) {
|
|
250
|
-
this._elseViewRef = this._viewContainer.createEmbeddedView(this._elseTemplateRef);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
ngOnDestroy() {
|
|
256
|
-
this._change$.unsubscribe();
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
ACLIfDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.
|
|
260
|
-
ACLIfDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.
|
|
261
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.
|
|
262
|
-
type: Directive,
|
|
263
|
-
args: [{
|
|
264
|
-
selector: '[aclIf]',
|
|
265
|
-
exportAs: 'aclIf'
|
|
266
|
-
}]
|
|
267
|
-
}], ctorParameters: function () { return [{ type: i0.TemplateRef }, { type: ACLService }, { type: i0.ViewContainerRef }]; }, propDecorators: { aclIf: [{
|
|
268
|
-
type: Input
|
|
269
|
-
}], aclIfThen: [{
|
|
270
|
-
type: Input
|
|
271
|
-
}], aclIfElse: [{
|
|
272
|
-
type: Input
|
|
273
|
-
}], except: [{
|
|
274
|
-
type: Input
|
|
275
|
-
}] } });
|
|
276
|
-
|
|
277
|
-
class ACLDirective {
|
|
278
|
-
set acl(value) {
|
|
279
|
-
this.set(value);
|
|
280
|
-
}
|
|
281
|
-
set ability(value) {
|
|
282
|
-
this.set(this.srv.parseAbility(value));
|
|
283
|
-
}
|
|
284
|
-
set(value) {
|
|
285
|
-
this._value = value;
|
|
286
|
-
const CLS = 'acl__hide';
|
|
287
|
-
const el = this.el.nativeElement;
|
|
288
|
-
if (this.srv.can(this._value)) {
|
|
289
|
-
this.renderer.removeClass(el, CLS);
|
|
290
|
-
}
|
|
291
|
-
else {
|
|
292
|
-
this.renderer.addClass(el, CLS);
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
constructor(el, renderer, srv) {
|
|
296
|
-
this.el = el;
|
|
297
|
-
this.renderer = renderer;
|
|
298
|
-
this.srv = srv;
|
|
299
|
-
this.change$ = this.srv.change.pipe(filter(r => r != null)).subscribe(() => this.set(this._value));
|
|
300
|
-
}
|
|
301
|
-
ngOnDestroy() {
|
|
302
|
-
this.change$.unsubscribe();
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
ACLDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.
|
|
306
|
-
ACLDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.
|
|
307
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.
|
|
308
|
-
type: Directive,
|
|
309
|
-
args: [{
|
|
310
|
-
selector: '[acl]',
|
|
311
|
-
exportAs: 'acl'
|
|
312
|
-
}]
|
|
313
|
-
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: ACLService }]; }, propDecorators: { acl: [{
|
|
314
|
-
type: Input,
|
|
315
|
-
args: ['acl']
|
|
316
|
-
}], ability: [{
|
|
317
|
-
type: Input,
|
|
318
|
-
args: ['acl-ability']
|
|
319
|
-
}] } });
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* Routing guard prevent unauthorized users visit the page, [ACL Document](https://ng.yunzainfo.com/acl).
|
|
323
|
-
*
|
|
324
|
-
* ```ts
|
|
325
|
-
* data: {
|
|
326
|
-
* path: 'home',
|
|
327
|
-
* canActivate: [ ACLGuard ],
|
|
328
|
-
* data: { guard: 'user1' }
|
|
329
|
-
* }
|
|
330
|
-
* ```
|
|
331
|
-
*/
|
|
332
|
-
class ACLGuard {
|
|
333
|
-
constructor(srv, router, injector) {
|
|
334
|
-
this.srv = srv;
|
|
335
|
-
this.router = router;
|
|
336
|
-
this.injector = injector;
|
|
337
|
-
}
|
|
338
|
-
process(data) {
|
|
339
|
-
data = Object.assign({ guard: null, guard_url: this.srv.guard_url }, data);
|
|
340
|
-
let guard = data.guard;
|
|
341
|
-
if (typeof guard === 'function')
|
|
342
|
-
guard = guard(this.srv, this.injector);
|
|
343
|
-
return (guard && guard instanceof Observable ? guard : of(guard != null ? guard : null)).pipe(map(v => this.srv.can(v)), tap(v => {
|
|
344
|
-
if (v)
|
|
345
|
-
return;
|
|
346
|
-
this.router.navigateByUrl(data.guard_url);
|
|
347
|
-
}));
|
|
348
|
-
}
|
|
349
|
-
// lazy loading
|
|
350
|
-
|
|
351
|
-
return this.process(route.data);
|
|
352
|
-
}
|
|
353
|
-
// all children route
|
|
354
|
-
canActivateChild(childRoute, state) {
|
|
355
|
-
return this.canActivate(childRoute, state);
|
|
356
|
-
}
|
|
357
|
-
// route
|
|
358
|
-
canActivate(route, _state) {
|
|
359
|
-
return this.process(route.data);
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
ACLGuard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.
|
|
363
|
-
ACLGuard.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.
|
|
364
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.
|
|
365
|
-
type: Injectable,
|
|
366
|
-
args: [{ providedIn: 'root' }]
|
|
367
|
-
}], ctorParameters: function () { return [{ type: ACLService }, { type: i2.Router }, { type: i0.Injector }]; } });
|
|
368
|
-
|
|
369
|
-
const COMPONENTS = [ACLDirective, ACLIfDirective];
|
|
370
|
-
class YelonACLModule {
|
|
371
|
-
static forRoot() {
|
|
372
|
-
return {
|
|
373
|
-
ngModule: YelonACLModule,
|
|
374
|
-
providers: [ACLService]
|
|
375
|
-
};
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
YelonACLModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.
|
|
379
|
-
YelonACLModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.
|
|
380
|
-
YelonACLModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.
|
|
381
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.
|
|
382
|
-
type: NgModule,
|
|
383
|
-
args: [{
|
|
384
|
-
imports: [CommonModule],
|
|
385
|
-
declarations: COMPONENTS,
|
|
386
|
-
exports: COMPONENTS
|
|
387
|
-
}]
|
|
388
|
-
}] });
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Generated bundle index. Do not edit.
|
|
392
|
-
*/
|
|
393
|
-
|
|
394
|
-
export { ACLDirective, ACLGuard, ACLIfDirective, ACLService, ACL_DEFAULT_CONFIG, YelonACLModule };
|
|
395
|
-
//# sourceMappingURL=acl.mjs.map
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { Injectable, Directive, Input, NgModule } from '@angular/core';
|
|
3
|
+
import { BehaviorSubject, filter, Observable, of, map, tap } from 'rxjs';
|
|
4
|
+
import * as i1 from '@yelon/util/config';
|
|
5
|
+
import * as i2 from '@angular/router';
|
|
6
|
+
import { CommonModule } from '@angular/common';
|
|
7
|
+
|
|
8
|
+
const ACL_DEFAULT_CONFIG = {
|
|
9
|
+
guard_url: `/403`
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* ACL 控制服务,[在线文档](https://ng.yunzainfo.com/acl)
|
|
14
|
+
*
|
|
15
|
+
* 务必在根目录注册 `YelonACLModule.forRoot()` 才能使用服务
|
|
16
|
+
*/
|
|
17
|
+
class ACLService {
|
|
18
|
+
/** ACL变更通知 */
|
|
19
|
+
get change() {
|
|
20
|
+
return this.aclChange.asObservable();
|
|
21
|
+
}
|
|
22
|
+
/** 获取所有数据 */
|
|
23
|
+
get data() {
|
|
24
|
+
return {
|
|
25
|
+
full: this.full,
|
|
26
|
+
roles: this.roles,
|
|
27
|
+
abilities: this.abilities
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
get guard_url() {
|
|
31
|
+
return this.options.guard_url;
|
|
32
|
+
}
|
|
33
|
+
constructor(configSrv) {
|
|
34
|
+
this.roles = [];
|
|
35
|
+
this.abilities = [];
|
|
36
|
+
this.full = false;
|
|
37
|
+
this.aclChange = new BehaviorSubject(null);
|
|
38
|
+
this.options = configSrv.merge('acl', ACL_DEFAULT_CONFIG);
|
|
39
|
+
}
|
|
40
|
+
parseACLType(val) {
|
|
41
|
+
let t;
|
|
42
|
+
if (typeof val === 'number') {
|
|
43
|
+
t = { ability: [val] };
|
|
44
|
+
}
|
|
45
|
+
else if (Array.isArray(val) && val.length > 0 && typeof val[0] === 'number') {
|
|
46
|
+
t = { ability: val };
|
|
47
|
+
}
|
|
48
|
+
else if (typeof val === 'object' && !Array.isArray(val)) {
|
|
49
|
+
t = Object.assign({}, val);
|
|
50
|
+
}
|
|
51
|
+
else if (Array.isArray(val)) {
|
|
52
|
+
t = { role: val };
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
t = { role: val == null ? [] : [val] };
|
|
56
|
+
}
|
|
57
|
+
return Object.assign({ except: false }, t);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 设置当前用户角色或权限能力(会先清除所有)
|
|
61
|
+
*/
|
|
62
|
+
set(value) {
|
|
63
|
+
this.full = false;
|
|
64
|
+
this.abilities = [];
|
|
65
|
+
this.roles = [];
|
|
66
|
+
this.add(value);
|
|
67
|
+
this.aclChange.next(value);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* 标识当前用户为全量,即不受限
|
|
71
|
+
*/
|
|
72
|
+
setFull(val) {
|
|
73
|
+
this.full = val;
|
|
74
|
+
this.aclChange.next(val);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* 设置当前用户权限能力(会先清除所有)
|
|
78
|
+
*/
|
|
79
|
+
setAbility(abilities) {
|
|
80
|
+
this.set({ ability: abilities });
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 设置当前用户角色(会先清除所有)
|
|
84
|
+
*/
|
|
85
|
+
setRole(roles) {
|
|
86
|
+
this.set({ role: roles });
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* 为当前用户增加角色或权限能力
|
|
90
|
+
*/
|
|
91
|
+
add(value) {
|
|
92
|
+
if (value.role && value.role.length > 0) {
|
|
93
|
+
this.roles.push(...value.role);
|
|
94
|
+
}
|
|
95
|
+
if (value.ability && value.ability.length > 0) {
|
|
96
|
+
this.abilities.push(...value.ability);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* 为当前用户附加角色
|
|
101
|
+
*/
|
|
102
|
+
attachRole(roles) {
|
|
103
|
+
for (const val of roles) {
|
|
104
|
+
if (!this.roles.includes(val)) {
|
|
105
|
+
this.roles.push(val);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
this.aclChange.next(this.data);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* 为当前用户附加权限
|
|
112
|
+
*/
|
|
113
|
+
attachAbility(abilities) {
|
|
114
|
+
for (const val of abilities) {
|
|
115
|
+
if (!this.abilities.includes(val)) {
|
|
116
|
+
this.abilities.push(val);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
this.aclChange.next(this.data);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* 为当前用户移除角色
|
|
123
|
+
*/
|
|
124
|
+
removeRole(roles) {
|
|
125
|
+
for (const val of roles) {
|
|
126
|
+
const idx = this.roles.indexOf(val);
|
|
127
|
+
if (idx !== -1) {
|
|
128
|
+
this.roles.splice(idx, 1);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
this.aclChange.next(this.data);
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* 为当前用户移除权限
|
|
135
|
+
*/
|
|
136
|
+
removeAbility(abilities) {
|
|
137
|
+
for (const val of abilities) {
|
|
138
|
+
const idx = this.abilities.indexOf(val);
|
|
139
|
+
if (idx !== -1) {
|
|
140
|
+
this.abilities.splice(idx, 1);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
this.aclChange.next(this.data);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* 当前用户是否有对应角色,其实 `number` 表示Ability
|
|
147
|
+
*
|
|
148
|
+
* - 当 `full: true` 或参数 `null` 时返回 `true`
|
|
149
|
+
* - 若使用 `ACLType` 参数,可以指定 `mode` 校验模式
|
|
150
|
+
*/
|
|
151
|
+
can(roleOrAbility) {
|
|
152
|
+
const { preCan } = this.options;
|
|
153
|
+
if (preCan) {
|
|
154
|
+
roleOrAbility = preCan(roleOrAbility);
|
|
155
|
+
}
|
|
156
|
+
const t = this.parseACLType(roleOrAbility);
|
|
157
|
+
let result = false;
|
|
158
|
+
if (this.full === true || !roleOrAbility) {
|
|
159
|
+
result = true;
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
if (t.role && t.role.length > 0) {
|
|
163
|
+
if (t.mode === 'allOf') {
|
|
164
|
+
result = t.role.every(v => this.roles.includes(v));
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
result = t.role.some(v => this.roles.includes(v));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (t.ability && t.ability.length > 0) {
|
|
171
|
+
if (t.mode === 'allOf') {
|
|
172
|
+
result = t.ability.every(v => this.abilities.includes(v));
|
|
173
|
+
}
|
|
174
|
+
else {
|
|
175
|
+
result = t.ability.some(v => this.abilities.includes(v));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return t.except === true ? !result : result;
|
|
180
|
+
}
|
|
181
|
+
/** @inner */
|
|
182
|
+
parseAbility(value) {
|
|
183
|
+
if (typeof value === 'number' || typeof value === 'string' || Array.isArray(value)) {
|
|
184
|
+
value = { ability: Array.isArray(value) ? value : [value] };
|
|
185
|
+
}
|
|
186
|
+
delete value.role;
|
|
187
|
+
return value;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* 当前用户是否有对应权限点
|
|
191
|
+
*/
|
|
192
|
+
canAbility(value) {
|
|
193
|
+
return this.can(this.parseAbility(value));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
ACLService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ACLService, deps: [{ token: i1.YunzaiConfigService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
197
|
+
ACLService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ACLService });
|
|
198
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ACLService, decorators: [{
|
|
199
|
+
type: Injectable
|
|
200
|
+
}], ctorParameters: function () { return [{ type: i1.YunzaiConfigService }]; } });
|
|
201
|
+
|
|
202
|
+
class ACLIfDirective {
|
|
203
|
+
constructor(templateRef, srv, _viewContainer) {
|
|
204
|
+
this.srv = srv;
|
|
205
|
+
this._viewContainer = _viewContainer;
|
|
206
|
+
this._thenTemplateRef = null;
|
|
207
|
+
this._elseTemplateRef = null;
|
|
208
|
+
this._thenViewRef = null;
|
|
209
|
+
this._elseViewRef = null;
|
|
210
|
+
this._except = false;
|
|
211
|
+
this._change$ = this.srv.change.pipe(filter(r => r != null)).subscribe(() => this._updateView());
|
|
212
|
+
this._thenTemplateRef = templateRef;
|
|
213
|
+
}
|
|
214
|
+
set aclIf(value) {
|
|
215
|
+
this._value = value;
|
|
216
|
+
this._updateView();
|
|
217
|
+
}
|
|
218
|
+
set aclIfThen(templateRef) {
|
|
219
|
+
this._thenTemplateRef = templateRef;
|
|
220
|
+
this._thenViewRef = null;
|
|
221
|
+
this._updateView();
|
|
222
|
+
}
|
|
223
|
+
set aclIfElse(templateRef) {
|
|
224
|
+
this._elseTemplateRef = templateRef;
|
|
225
|
+
this._elseViewRef = null;
|
|
226
|
+
this._updateView();
|
|
227
|
+
}
|
|
228
|
+
set except(value) {
|
|
229
|
+
this._except = value != null && `${value}` !== 'false';
|
|
230
|
+
}
|
|
231
|
+
get except() {
|
|
232
|
+
return this._except;
|
|
233
|
+
}
|
|
234
|
+
_updateView() {
|
|
235
|
+
const res = this.srv.can(this._value);
|
|
236
|
+
if ((res && !this.except) || (!res && this.except)) {
|
|
237
|
+
if (!this._thenViewRef) {
|
|
238
|
+
this._viewContainer.clear();
|
|
239
|
+
this._elseViewRef = null;
|
|
240
|
+
if (this._thenTemplateRef) {
|
|
241
|
+
this._thenViewRef = this._viewContainer.createEmbeddedView(this._thenTemplateRef);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
if (!this._elseViewRef) {
|
|
247
|
+
this._viewContainer.clear();
|
|
248
|
+
this._thenViewRef = null;
|
|
249
|
+
if (this._elseTemplateRef) {
|
|
250
|
+
this._elseViewRef = this._viewContainer.createEmbeddedView(this._elseTemplateRef);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
ngOnDestroy() {
|
|
256
|
+
this._change$.unsubscribe();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
ACLIfDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ACLIfDirective, deps: [{ token: i0.TemplateRef }, { token: ACLService }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive });
|
|
260
|
+
ACLIfDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: ACLIfDirective, selector: "[aclIf]", inputs: { aclIf: "aclIf", aclIfThen: "aclIfThen", aclIfElse: "aclIfElse", except: "except" }, exportAs: ["aclIf"], ngImport: i0 });
|
|
261
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ACLIfDirective, decorators: [{
|
|
262
|
+
type: Directive,
|
|
263
|
+
args: [{
|
|
264
|
+
selector: '[aclIf]',
|
|
265
|
+
exportAs: 'aclIf'
|
|
266
|
+
}]
|
|
267
|
+
}], ctorParameters: function () { return [{ type: i0.TemplateRef }, { type: ACLService }, { type: i0.ViewContainerRef }]; }, propDecorators: { aclIf: [{
|
|
268
|
+
type: Input
|
|
269
|
+
}], aclIfThen: [{
|
|
270
|
+
type: Input
|
|
271
|
+
}], aclIfElse: [{
|
|
272
|
+
type: Input
|
|
273
|
+
}], except: [{
|
|
274
|
+
type: Input
|
|
275
|
+
}] } });
|
|
276
|
+
|
|
277
|
+
class ACLDirective {
|
|
278
|
+
set acl(value) {
|
|
279
|
+
this.set(value);
|
|
280
|
+
}
|
|
281
|
+
set ability(value) {
|
|
282
|
+
this.set(this.srv.parseAbility(value));
|
|
283
|
+
}
|
|
284
|
+
set(value) {
|
|
285
|
+
this._value = value;
|
|
286
|
+
const CLS = 'acl__hide';
|
|
287
|
+
const el = this.el.nativeElement;
|
|
288
|
+
if (this.srv.can(this._value)) {
|
|
289
|
+
this.renderer.removeClass(el, CLS);
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
this.renderer.addClass(el, CLS);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
constructor(el, renderer, srv) {
|
|
296
|
+
this.el = el;
|
|
297
|
+
this.renderer = renderer;
|
|
298
|
+
this.srv = srv;
|
|
299
|
+
this.change$ = this.srv.change.pipe(filter(r => r != null)).subscribe(() => this.set(this._value));
|
|
300
|
+
}
|
|
301
|
+
ngOnDestroy() {
|
|
302
|
+
this.change$.unsubscribe();
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
ACLDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ACLDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: ACLService }], target: i0.ɵɵFactoryTarget.Directive });
|
|
306
|
+
ACLDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.9", type: ACLDirective, selector: "[acl]", inputs: { acl: "acl", ability: ["acl-ability", "ability"] }, exportAs: ["acl"], ngImport: i0 });
|
|
307
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ACLDirective, decorators: [{
|
|
308
|
+
type: Directive,
|
|
309
|
+
args: [{
|
|
310
|
+
selector: '[acl]',
|
|
311
|
+
exportAs: 'acl'
|
|
312
|
+
}]
|
|
313
|
+
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: ACLService }]; }, propDecorators: { acl: [{
|
|
314
|
+
type: Input,
|
|
315
|
+
args: ['acl']
|
|
316
|
+
}], ability: [{
|
|
317
|
+
type: Input,
|
|
318
|
+
args: ['acl-ability']
|
|
319
|
+
}] } });
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Routing guard prevent unauthorized users visit the page, [ACL Document](https://ng.yunzainfo.com/acl).
|
|
323
|
+
*
|
|
324
|
+
* ```ts
|
|
325
|
+
* data: {
|
|
326
|
+
* path: 'home',
|
|
327
|
+
* canActivate: [ ACLGuard ],
|
|
328
|
+
* data: { guard: 'user1' }
|
|
329
|
+
* }
|
|
330
|
+
* ```
|
|
331
|
+
*/
|
|
332
|
+
class ACLGuard {
|
|
333
|
+
constructor(srv, router, injector) {
|
|
334
|
+
this.srv = srv;
|
|
335
|
+
this.router = router;
|
|
336
|
+
this.injector = injector;
|
|
337
|
+
}
|
|
338
|
+
process(data) {
|
|
339
|
+
data = Object.assign({ guard: null, guard_url: this.srv.guard_url }, data);
|
|
340
|
+
let guard = data.guard;
|
|
341
|
+
if (typeof guard === 'function')
|
|
342
|
+
guard = guard(this.srv, this.injector);
|
|
343
|
+
return (guard && guard instanceof Observable ? guard : of(guard != null ? guard : null)).pipe(map(v => this.srv.can(v)), tap(v => {
|
|
344
|
+
if (v)
|
|
345
|
+
return;
|
|
346
|
+
this.router.navigateByUrl(data.guard_url);
|
|
347
|
+
}));
|
|
348
|
+
}
|
|
349
|
+
// lazy loading
|
|
350
|
+
canMatch(route) {
|
|
351
|
+
return this.process(route.data);
|
|
352
|
+
}
|
|
353
|
+
// all children route
|
|
354
|
+
canActivateChild(childRoute, state) {
|
|
355
|
+
return this.canActivate(childRoute, state);
|
|
356
|
+
}
|
|
357
|
+
// route
|
|
358
|
+
canActivate(route, _state) {
|
|
359
|
+
return this.process(route.data);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
ACLGuard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ACLGuard, deps: [{ token: ACLService }, { token: i2.Router }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
363
|
+
ACLGuard.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ACLGuard, providedIn: 'root' });
|
|
364
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: ACLGuard, decorators: [{
|
|
365
|
+
type: Injectable,
|
|
366
|
+
args: [{ providedIn: 'root' }]
|
|
367
|
+
}], ctorParameters: function () { return [{ type: ACLService }, { type: i2.Router }, { type: i0.Injector }]; } });
|
|
368
|
+
|
|
369
|
+
const COMPONENTS = [ACLDirective, ACLIfDirective];
|
|
370
|
+
class YelonACLModule {
|
|
371
|
+
static forRoot() {
|
|
372
|
+
return {
|
|
373
|
+
ngModule: YelonACLModule,
|
|
374
|
+
providers: [ACLService]
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
YelonACLModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: YelonACLModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
379
|
+
YelonACLModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.9", ngImport: i0, type: YelonACLModule, declarations: [ACLDirective, ACLIfDirective], imports: [CommonModule], exports: [ACLDirective, ACLIfDirective] });
|
|
380
|
+
YelonACLModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: YelonACLModule, imports: [CommonModule] });
|
|
381
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.9", ngImport: i0, type: YelonACLModule, decorators: [{
|
|
382
|
+
type: NgModule,
|
|
383
|
+
args: [{
|
|
384
|
+
imports: [CommonModule],
|
|
385
|
+
declarations: COMPONENTS,
|
|
386
|
+
exports: COMPONENTS
|
|
387
|
+
}]
|
|
388
|
+
}] });
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Generated bundle index. Do not edit.
|
|
392
|
+
*/
|
|
393
|
+
|
|
394
|
+
export { ACLDirective, ACLGuard, ACLIfDirective, ACLService, ACL_DEFAULT_CONFIG, YelonACLModule };
|
|
395
|
+
//# sourceMappingURL=acl.mjs.map
|