@reskin/core 0.0.22 → 0.1.0

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.
Files changed (45) hide show
  1. package/bundles/reskin-core-directives.umd.js +303 -163
  2. package/bundles/reskin-core-directives.umd.js.map +1 -1
  3. package/bundles/reskin-core-guards.umd.js +119 -32
  4. package/bundles/reskin-core-guards.umd.js.map +1 -1
  5. package/bundles/reskin-core-interceptors.umd.js +286 -104
  6. package/bundles/reskin-core-interceptors.umd.js.map +1 -1
  7. package/bundles/reskin-core-utils.umd.js +220 -77
  8. package/bundles/reskin-core-utils.umd.js.map +1 -1
  9. package/directives/auth.directive.d.ts +56 -9
  10. package/directives/load.styles.directive.d.ts +45 -5
  11. package/directives/string.template.outlet.directive.d.ts +68 -11
  12. package/esm2015/directives/auth.directive.js +71 -30
  13. package/esm2015/directives/load.styles.directive.js +84 -15
  14. package/esm2015/directives/string.template.outlet.directive.js +118 -60
  15. package/esm2015/guards/auth.guard.js +117 -30
  16. package/esm2015/interceptors/blob.interceptor.js +67 -28
  17. package/esm2015/interceptors/cache.interceptor.js +46 -14
  18. package/esm2015/interceptors/error.interceptor.js +104 -12
  19. package/esm2015/interceptors/public-api.js +2 -1
  20. package/esm2015/interceptors/token.interceptor.js +66 -53
  21. package/esm2015/interceptors/types.js +5 -0
  22. package/esm2015/utils/array.js +42 -22
  23. package/esm2015/utils/dom.js +29 -11
  24. package/esm2015/utils/form.js +44 -13
  25. package/esm2015/utils/store.js +101 -26
  26. package/fesm2015/reskin-core-directives.js +269 -103
  27. package/fesm2015/reskin-core-directives.js.map +1 -1
  28. package/fesm2015/reskin-core-guards.js +116 -29
  29. package/fesm2015/reskin-core-guards.js.map +1 -1
  30. package/fesm2015/reskin-core-interceptors.js +282 -102
  31. package/fesm2015/reskin-core-interceptors.js.map +1 -1
  32. package/fesm2015/reskin-core-utils.js +212 -68
  33. package/fesm2015/reskin-core-utils.js.map +1 -1
  34. package/guards/auth.guard.d.ts +85 -5
  35. package/interceptors/blob.interceptor.d.ts +30 -3
  36. package/interceptors/cache.interceptor.d.ts +28 -4
  37. package/interceptors/error.interceptor.d.ts +43 -2
  38. package/interceptors/public-api.d.ts +1 -0
  39. package/interceptors/token.interceptor.d.ts +35 -18
  40. package/interceptors/types.d.ts +68 -0
  41. package/package.json +1 -1
  42. package/utils/array.d.ts +8 -1
  43. package/utils/dom.d.ts +32 -5
  44. package/utils/form.d.ts +37 -2
  45. package/utils/store.d.ts +56 -15
@@ -1,5 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, Injectable, Inject } from '@angular/core';
2
+ import { InjectionToken, Injectable, Optional, Inject } from '@angular/core';
3
+ import { of } from 'rxjs';
3
4
  import { filter, map, catchError } from 'rxjs/operators';
4
5
  import * as i1 from '@reskin/core/services';
5
6
  import * as i2 from '@angular/router';
@@ -8,60 +9,139 @@ import * as i2 from '@angular/router';
8
9
  * 路由守卫配置注入令牌
9
10
  */
10
11
  const RK_ROUTER_GUARD_CONFIG = new InjectionToken('router_guard_config');
12
+ /**
13
+ * 路由守卫选项注入令牌
14
+ */
15
+ const RK_ROUTER_GUARD_OPTIONS = new InjectionToken('router_guard_options');
11
16
  /**
12
17
  * 路由守卫提供者配置函数
13
18
  *
14
19
  * @param urls - 路由守卫配置数组,包含需要保护的路由配置信息
20
+ * @param options - 可选的守卫选项配置
15
21
  * @returns 返回Angular依赖注入的Provider数组,用于配置路由守卫
16
22
  */
17
- function providerRouterGuard(urls) {
18
- return [
19
- // 路由守卫配置
20
- { provide: RK_ROUTER_GUARD_CONFIG, useValue: urls },
21
- ];
23
+ function providerRouterGuard(urls, options) {
24
+ const providers = [{ provide: RK_ROUTER_GUARD_CONFIG, useValue: urls }];
25
+ if (options) {
26
+ providers.push({ provide: RK_ROUTER_GUARD_OPTIONS, useValue: options });
27
+ }
28
+ return providers;
22
29
  }
30
+ /**
31
+ * 路由权限守卫
32
+ *
33
+ * 用于保护路由,确保用户只能访问其被授权的路由。
34
+ * 支持权限继承机制和自定义权限检查逻辑。
35
+ */
23
36
  class RkAuthGuard {
24
- constructor(config, menu, router) {
37
+ constructor(config, options, menu, router) {
25
38
  this.config = config;
39
+ this.options = options;
26
40
  this.menu = menu;
27
41
  this.router = router;
28
42
  }
29
43
  canActivateChild(childRoute, state) {
30
- return this.menu.requestData().pipe(filter((json) => json.code === 0), map((json) => json.data), map((menus) => this.checkAccess(menus, childRoute, state.url)), catchError(() => {
31
- this.handleNoAccess(state.url);
32
- return [false];
44
+ var _a;
45
+ // 检查路由数据中是否配置跳过权限检查
46
+ if (childRoute.data['skipAuth'] === true) {
47
+ return true;
48
+ }
49
+ // 执行前置钩子
50
+ if (((_a = this.options) === null || _a === void 0 ? void 0 : _a.beforeCheck) && !this.options.beforeCheck(childRoute, state)) {
51
+ return this.handleNoAccess(state.url);
52
+ }
53
+ return this.menu.requestData().pipe(filter((json) => json.code === 0), map((json) => json.data), map((menus) => this.checkAccess(menus, state.url)), catchError((error) => {
54
+ console.error('路由权限检查失败:', error);
55
+ return of(this.handleNoAccess(state.url));
33
56
  }));
34
57
  }
35
- checkAccess(menus, childRoute, url) {
36
- if (!menus.length) {
37
- throw new Error(`此账号无任何功能权限.`);
58
+ /**
59
+ * 检查用户是否有权限访问指定路由
60
+ *
61
+ * @param menus - 用户菜单权限数据
62
+ * @param url - 目标路由地址
63
+ * @returns 返回 true 允许访问,返回 false 或 UrlTree 拒绝访问
64
+ */
65
+ checkAccess(menus, url) {
66
+ if (!menus || menus.length === 0) {
67
+ console.error('此账号无任何功能权限');
68
+ return this.handleNoAccess(url);
38
69
  }
39
- const routerUrl = url.replace(/\?.*/, '');
70
+ // 移除查询参数,只保留路径部分
71
+ const routerUrl = this.normalizeUrl(url);
72
+ // 构建用户权限路由集合
40
73
  const authRoutes = new Set(menus.map((m) => m.SYSTEM_RESOURCE_URL));
74
+ // 直接权限检查
41
75
  if (authRoutes.has(routerUrl)) {
42
76
  return true;
43
77
  }
44
- if (this.config && this.config.length > 0) {
45
- const extendRoutes = this.config.filter((item) => {
46
- return item.extends.some((route) => (route.includes('**') ? this.match(route, routerUrl) : route === routerUrl));
47
- });
48
- if (extendRoutes.length > 0) {
49
- return extendRoutes.some((item) => authRoutes.has(item.url));
50
- }
78
+ // 继承权限检查
79
+ if (this.hasInheritedPermission(routerUrl, authRoutes)) {
80
+ return true;
81
+ }
82
+ // 无权限访问
83
+ return this.handleNoAccess(url);
84
+ }
85
+ /**
86
+ * 检查是否有继承的权限
87
+ *
88
+ * @param routerUrl - 标准化后的路由地址
89
+ * @param authRoutes - 用户权限路由集合
90
+ * @returns 返回 true 表示有继承权限
91
+ */
92
+ hasInheritedPermission(routerUrl, authRoutes) {
93
+ if (!this.config || this.config.length === 0) {
94
+ return false;
95
+ }
96
+ // 查找匹配的继承配置
97
+ const matchedConfigs = this.config.filter((item) => {
98
+ return item.extends.some((route) => this.matchRoute(route, routerUrl));
99
+ });
100
+ // 检查是否有任一配置的 url 在用户权限中
101
+ return matchedConfigs.some((item) => authRoutes.has(item.url));
102
+ }
103
+ /**
104
+ * 匹配路由规则
105
+ *
106
+ * @param pattern - 路由模式(支持 ** 通配符)
107
+ * @param path - 实际路由路径
108
+ * @returns 返回 true 表示匹配成功
109
+ */
110
+ matchRoute(pattern, path) {
111
+ if (pattern.includes('**')) {
112
+ const regexPattern = pattern.replace(/\*\*/g, '.*');
113
+ return new RegExp(`^${regexPattern}$`).test(path);
51
114
  }
52
- this.handleNoAccess(url);
53
- return false;
115
+ return pattern === path;
54
116
  }
55
- match(pattern, path) {
56
- const regexPattern = pattern.replace(/\*\*/g, '.*');
57
- return new RegExp(`^${regexPattern}$`).test(path);
117
+ /**
118
+ * 标准化URL,移除查询参数和片段标识符
119
+ *
120
+ * @param url - 原始URL
121
+ * @returns 标准化后的URL
122
+ */
123
+ normalizeUrl(url) {
124
+ return url.replace(/[?#].*/, '');
58
125
  }
126
+ /**
127
+ * 处理无权限访问
128
+ *
129
+ * @param url - 被拒绝访问的路由地址
130
+ * @returns 返回 false 或 UrlTree
131
+ */
59
132
  handleNoAccess(url) {
133
+ var _a, _b;
60
134
  console.error(`无权限访问路由地址: ${url}`);
61
- this.router.navigate(['/errors/401']).then();
135
+ // 使用自定义回调
136
+ if ((_a = this.options) === null || _a === void 0 ? void 0 : _a.onAccessDenied) {
137
+ return this.options.onAccessDenied(url);
138
+ }
139
+ // 使用自定义未授权路径或默认路径
140
+ const unauthorizedPath = ((_b = this.options) === null || _b === void 0 ? void 0 : _b.unauthorizedPath) || '/errors/401';
141
+ return this.router.createUrlTree([unauthorizedPath]);
62
142
  }
63
143
  }
64
- RkAuthGuard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: RkAuthGuard, deps: [{ token: RK_ROUTER_GUARD_CONFIG }, { token: i1.RkMenuService }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Injectable });
144
+ RkAuthGuard.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: RkAuthGuard, deps: [{ token: RK_ROUTER_GUARD_CONFIG, optional: true }, { token: RK_ROUTER_GUARD_OPTIONS, optional: true }, { token: i1.RkMenuService }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Injectable });
65
145
  RkAuthGuard.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: RkAuthGuard, providedIn: 'root' });
66
146
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: RkAuthGuard, decorators: [{
67
147
  type: Injectable,
@@ -69,13 +149,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImpo
69
149
  providedIn: 'root',
70
150
  }]
71
151
  }], ctorParameters: function () { return [{ type: undefined, decorators: [{
152
+ type: Optional
153
+ }, {
72
154
  type: Inject,
73
155
  args: [RK_ROUTER_GUARD_CONFIG]
156
+ }] }, { type: undefined, decorators: [{
157
+ type: Optional
158
+ }, {
159
+ type: Inject,
160
+ args: [RK_ROUTER_GUARD_OPTIONS]
74
161
  }] }, { type: i1.RkMenuService }, { type: i2.Router }]; } });
75
162
 
76
163
  /**
77
164
  * Generated bundle index. Do not edit.
78
165
  */
79
166
 
80
- export { RK_ROUTER_GUARD_CONFIG, RkAuthGuard, providerRouterGuard };
167
+ export { RK_ROUTER_GUARD_CONFIG, RK_ROUTER_GUARD_OPTIONS, RkAuthGuard, providerRouterGuard };
81
168
  //# sourceMappingURL=reskin-core-guards.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"reskin-core-guards.js","sources":["../../../library/core/guards/auth.guard.ts","../../../library/core/guards/reskin-core-guards.ts"],"sourcesContent":["import { Inject, Injectable, InjectionToken, Provider } from '@angular/core';\r\nimport { ActivatedRouteSnapshot, CanActivateChild, Router, RouterStateSnapshot, UrlTree } from '@angular/router';\r\nimport { Observable } from 'rxjs';\r\nimport { filter, map, catchError } from 'rxjs/operators';\r\nimport { RkMenuService } from '@reskin/core/services';\r\n\r\n/**\r\n * 路由守卫配置注入令牌\r\n */\r\nexport const RK_ROUTER_GUARD_CONFIG = new InjectionToken('router_guard_config');\r\n\r\n/**\r\n * 路由守卫配置\r\n */\r\nexport interface IRouterGuardConfig {\r\n /**\r\n * 路由地址\r\n */\r\n url: string;\r\n /**\r\n * 继承的权限\r\n */\r\n extends: string[];\r\n}\r\n\r\n/**\r\n * 路由守卫提供者配置函数\r\n *\r\n * @param urls - 路由守卫配置数组,包含需要保护的路由配置信息\r\n * @returns 返回Angular依赖注入的Provider数组,用于配置路由守卫\r\n */\r\nexport function providerRouterGuard(urls: IRouterGuardConfig[]): Provider[] {\r\n return [\r\n // 路由守卫配置\r\n { provide: RK_ROUTER_GUARD_CONFIG, useValue: urls },\r\n ];\r\n}\r\n\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class RkAuthGuard implements CanActivateChild {\r\n constructor(\r\n @Inject(RK_ROUTER_GUARD_CONFIG) private config: IRouterGuardConfig[],\r\n private menu: RkMenuService,\r\n private router: Router,\r\n ) {}\r\n\r\n canActivateChild(\r\n childRoute: ActivatedRouteSnapshot,\r\n state: RouterStateSnapshot,\r\n ): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\r\n return this.menu.requestData().pipe(\r\n filter((json) => json.code === 0),\r\n map((json) => json.data),\r\n map((menus) => this.checkAccess(menus, childRoute, state.url)),\r\n catchError(() => {\r\n this.handleNoAccess(state.url);\r\n return [false];\r\n }),\r\n );\r\n }\r\n\r\n private checkAccess(menus: any[], childRoute: ActivatedRouteSnapshot, url: string): boolean | UrlTree {\r\n if (!menus.length) {\r\n throw new Error(`此账号无任何功能权限.`);\r\n }\r\n\r\n const routerUrl = url.replace(/\\?.*/, '');\r\n const authRoutes = new Set<string>(menus.map((m) => m.SYSTEM_RESOURCE_URL));\r\n\r\n if (authRoutes.has(routerUrl)) {\r\n return true;\r\n }\r\n\r\n if (this.config && this.config.length > 0) {\r\n const extendRoutes = this.config.filter((item) => {\r\n return item.extends.some((route: string) => (route.includes('**') ? this.match(route, routerUrl) : route === routerUrl));\r\n });\r\n if (extendRoutes.length > 0) {\r\n return extendRoutes.some((item) => authRoutes.has(item.url));\r\n }\r\n }\r\n\r\n this.handleNoAccess(url);\r\n return false;\r\n }\r\n\r\n private match(pattern: string, path: string): boolean {\r\n const regexPattern = pattern.replace(/\\*\\*/g, '.*');\r\n return new RegExp(`^${regexPattern}$`).test(path);\r\n }\r\n\r\n private handleNoAccess(url: string): void {\r\n console.error(`无权限访问路由地址: ${url}`);\r\n this.router.navigate(['/errors/401']).then();\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"reskin-core-guards.js","sources":["../../../library/core/guards/auth.guard.ts","../../../library/core/guards/reskin-core-guards.ts"],"sourcesContent":["import { Inject, Injectable, InjectionToken, Optional, Provider } from '@angular/core';\r\nimport { ActivatedRouteSnapshot, CanActivateChild, Router, RouterStateSnapshot, UrlTree } from '@angular/router';\r\nimport { Observable, of } from 'rxjs';\r\nimport { catchError, filter, map } from 'rxjs/operators';\r\nimport { RkMenuService } from '@reskin/core/services';\r\n\r\n/**\r\n * 路由守卫配置注入令牌\r\n */\r\nexport const RK_ROUTER_GUARD_CONFIG = new InjectionToken<IRouterGuardConfig[]>('router_guard_config');\r\n\r\n/**\r\n * 路由守卫选项注入令牌\r\n */\r\nexport const RK_ROUTER_GUARD_OPTIONS = new InjectionToken<IAuthGuardOptions>('router_guard_options');\r\n\r\n/**\r\n * 菜单数据接口\r\n */\r\nexport interface IMenuData {\r\n /**\r\n * 系统资源URL\r\n */\r\n SYSTEM_RESOURCE_URL: string;\r\n [key: string]: any;\r\n}\r\n\r\n/**\r\n * 路由守卫配置\r\n */\r\nexport interface IRouterGuardConfig {\r\n /**\r\n * 路由地址\r\n */\r\n url: string;\r\n /**\r\n * 继承的权限\r\n */\r\n extends: string[];\r\n}\r\n\r\n/**\r\n * 路由守卫选项配置\r\n */\r\nexport interface IAuthGuardOptions {\r\n /**\r\n * 无权限时的跳转路径\r\n * @default '/errors/401'\r\n */\r\n unauthorizedPath?: string;\r\n /**\r\n * 自定义无权限处理回调\r\n * @param url - 被拒绝访问的路由地址\r\n * @returns 返回 false 阻止导航,返回 UrlTree 进行重定向,返回 true 允许访问\r\n */\r\n onAccessDenied?: (url: string) => boolean | UrlTree;\r\n /**\r\n * 权限检查前的钩子函数\r\n * @param route - 激活的路由快照\r\n * @param state - 路由状态快照\r\n * @returns 返回 false 跳过权限检查并拒绝访问,返回 true 继续权限检查\r\n */\r\n beforeCheck?: (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => boolean;\r\n}\r\n\r\n/**\r\n * 路由守卫提供者配置函数\r\n *\r\n * @param urls - 路由守卫配置数组,包含需要保护的路由配置信息\r\n * @param options - 可选的守卫选项配置\r\n * @returns 返回Angular依赖注入的Provider数组,用于配置路由守卫\r\n */\r\nexport function providerRouterGuard(urls: IRouterGuardConfig[], options?: IAuthGuardOptions): Provider[] {\r\n const providers: Provider[] = [{ provide: RK_ROUTER_GUARD_CONFIG, useValue: urls }];\r\n\r\n if (options) {\r\n providers.push({ provide: RK_ROUTER_GUARD_OPTIONS, useValue: options });\r\n }\r\n\r\n return providers;\r\n}\r\n\r\n/**\r\n * 路由权限守卫\r\n *\r\n * 用于保护路由,确保用户只能访问其被授权的路由。\r\n * 支持权限继承机制和自定义权限检查逻辑。\r\n */\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class RkAuthGuard implements CanActivateChild {\r\n constructor(\r\n @Optional() @Inject(RK_ROUTER_GUARD_CONFIG) private config: IRouterGuardConfig[] | null,\r\n @Optional() @Inject(RK_ROUTER_GUARD_OPTIONS) private options: IAuthGuardOptions | null,\r\n private menu: RkMenuService,\r\n private router: Router,\r\n ) {}\r\n\r\n canActivateChild(\r\n childRoute: ActivatedRouteSnapshot,\r\n state: RouterStateSnapshot,\r\n ): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\r\n // 检查路由数据中是否配置跳过权限检查\r\n if (childRoute.data['skipAuth'] === true) {\r\n return true;\r\n }\r\n\r\n // 执行前置钩子\r\n if (this.options?.beforeCheck && !this.options.beforeCheck(childRoute, state)) {\r\n return this.handleNoAccess(state.url);\r\n }\r\n\r\n return this.menu.requestData().pipe(\r\n filter((json) => json.code === 0),\r\n map((json) => json.data as IMenuData[]),\r\n map((menus) => this.checkAccess(menus, state.url)),\r\n catchError((error) => {\r\n console.error('路由权限检查失败:', error);\r\n return of(this.handleNoAccess(state.url));\r\n }),\r\n );\r\n }\r\n\r\n /**\r\n * 检查用户是否有权限访问指定路由\r\n *\r\n * @param menus - 用户菜单权限数据\r\n * @param url - 目标路由地址\r\n * @returns 返回 true 允许访问,返回 false 或 UrlTree 拒绝访问\r\n */\r\n private checkAccess(menus: IMenuData[], url: string): boolean | UrlTree {\r\n if (!menus || menus.length === 0) {\r\n console.error('此账号无任何功能权限');\r\n return this.handleNoAccess(url);\r\n }\r\n\r\n // 移除查询参数,只保留路径部分\r\n const routerUrl = this.normalizeUrl(url);\r\n\r\n // 构建用户权限路由集合\r\n const authRoutes = new Set<string>(menus.map((m) => m.SYSTEM_RESOURCE_URL));\r\n\r\n // 直接权限检查\r\n if (authRoutes.has(routerUrl)) {\r\n return true;\r\n }\r\n\r\n // 继承权限检查\r\n if (this.hasInheritedPermission(routerUrl, authRoutes)) {\r\n return true;\r\n }\r\n\r\n // 无权限访问\r\n return this.handleNoAccess(url);\r\n }\r\n\r\n /**\r\n * 检查是否有继承的权限\r\n *\r\n * @param routerUrl - 标准化后的路由地址\r\n * @param authRoutes - 用户权限路由集合\r\n * @returns 返回 true 表示有继承权限\r\n */\r\n private hasInheritedPermission(routerUrl: string, authRoutes: Set<string>): boolean {\r\n if (!this.config || this.config.length === 0) {\r\n return false;\r\n }\r\n\r\n // 查找匹配的继承配置\r\n const matchedConfigs = this.config.filter((item) => {\r\n return item.extends.some((route: string) => this.matchRoute(route, routerUrl));\r\n });\r\n\r\n // 检查是否有任一配置的 url 在用户权限中\r\n return matchedConfigs.some((item) => authRoutes.has(item.url));\r\n }\r\n\r\n /**\r\n * 匹配路由规则\r\n *\r\n * @param pattern - 路由模式(支持 ** 通配符)\r\n * @param path - 实际路由路径\r\n * @returns 返回 true 表示匹配成功\r\n */\r\n private matchRoute(pattern: string, path: string): boolean {\r\n if (pattern.includes('**')) {\r\n const regexPattern = pattern.replace(/\\*\\*/g, '.*');\r\n return new RegExp(`^${regexPattern}$`).test(path);\r\n }\r\n return pattern === path;\r\n }\r\n\r\n /**\r\n * 标准化URL,移除查询参数和片段标识符\r\n *\r\n * @param url - 原始URL\r\n * @returns 标准化后的URL\r\n */\r\n private normalizeUrl(url: string): string {\r\n return url.replace(/[?#].*/, '');\r\n }\r\n\r\n /**\r\n * 处理无权限访问\r\n *\r\n * @param url - 被拒绝访问的路由地址\r\n * @returns 返回 false 或 UrlTree\r\n */\r\n private handleNoAccess(url: string): boolean | UrlTree {\r\n console.error(`无权限访问路由地址: ${url}`);\r\n\r\n // 使用自定义回调\r\n if (this.options?.onAccessDenied) {\r\n return this.options.onAccessDenied(url);\r\n }\r\n\r\n // 使用自定义未授权路径或默认路径\r\n const unauthorizedPath = this.options?.unauthorizedPath || '/errors/401';\r\n return this.router.createUrlTree([unauthorizedPath]);\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}