UNPKG

@lcsf/acl

Version:

权限控制模块

456 lines (446 loc) 13.7 kB
import * as i0 from '@angular/core'; import { Injectable, Directive, ElementRef, Renderer2, Input, TemplateRef, ViewContainerRef, NgModule } from '@angular/core'; import { filter } from 'rxjs/operators'; import { BehaviorSubject } from 'rxjs'; import { CommonModule } from '@angular/common'; import * as i2 from '@angular/router'; import { Router } from '@angular/router'; /** * * 务必在根目录注册 `LcAclModule.forRoot()` 才能使用服务 */ class LcAClService { constructor() { this.roles = []; this.types = []; this.permissionGroups = []; this.authPaths = new Map(); this.full = false; this.aclChange = new BehaviorSubject(null); } /** ACL变更通知 */ get change() { return this.aclChange.asObservable(); } /** 获取所有数据 */ get data() { return { full: this.full, roles: this.roles, permissionGroups: this.permissionGroups, authPaths: this.authPaths, }; } parseLcACLType(val) { let t; if (typeof val === 'string') { if (val.indexOf('::') > -1) { // permissionGroup t = { permissions: [val] }; } else { // role t = { role: [val] }; } } else if (typeof val === 'object' && !Array.isArray(val)) { t = Object.assign({}, val); } else if (Array.isArray(val)) { if (val[0].toString().indexOf('::') > -1) { t = { permissions: val }; } else { t = { role: val }; } } else { t = { role: val == null ? [] : [val] }; } return Object.assign({ except: false }, t); } /** * 设置当前用户角色或权限能力(会先清除所有) */ set(value) { this.full = false; this.roles = []; this.types = []; this.permissionGroups = []; this.authPaths = new Map(); this.add(value); this.aclChange.next(value); } /** * 标识当前用户为全量,即不受限 */ setFull(val) { this.full = val; this.aclChange.next(val); } /** * 设置当前用户角色(会先清除所有) */ setRole(roles) { this.set({ role: roles }); } /** * 为当前用户增加角色或权限能力 */ add(value) { if (value.role && value.role.length > 0) { this.roles.push(...value.role); } if (value.type && value.type.length > 0) { this.types.push(...value.type); } if (value.permissionGroups && value.permissionGroups.length > 0) { this.permissionGroups.push(...value.permissionGroups); } if (value.menus && value.menus.length > 0) { this.authPaths = this.getAuthPaths(value.menus); } } /** * 为当前用户附加角色 */ attachRole(roles) { for (const val of roles) { if (!this.roles.includes(val)) { this.roles.push(val); } } this.aclChange.next(this.data); } /** * 为当前用户移除角色 */ removeRole(roles) { for (const val of roles) { const idx = this.roles.indexOf(val); if (idx !== -1) { this.roles.splice(idx, 1); } } this.aclChange.next(this.data); } /** * 当前用户是否有对应角色,其实 `number` 表示Ability * * - 当 `full: true` 或参数 `null` 时返回 `true` * - 若使用 `LcACLType` 参数,可以指定 `mode` 校验模式 */ can(roleOrAbility) { // debugger const t = this.parseLcACLType(roleOrAbility); let result = false; if (this.full === true || !roleOrAbility) { result = true; } else { if (t.role && t.role.length > 0) { if (typeof t.role === 'string') { t.role = [t.role]; } if (t.mode === 'allOf') { result = t.role.every(v => { if (v.toString().indexOf('-') > -1) { let arr = v.split('-'); return this.roles.includes(arr[0]) && this.types.includes(arr[1]); } return this.roles.includes(v); }); } else { result = t.role.some(v => { if (v.toString().indexOf('-') > -1) { let arr = v.split('-'); return this.roles.includes(arr[0]) && this.types.includes(arr[1]); } return this.roles.includes(v); }); } } if (t.permissions && t.permissions.length > 0) { if (typeof t.permissions === 'string') { t.permissions = [t.permissions]; } if (t.mode === 'allOf') { result = t.permissions.every(v => this.permissionGroups.includes(v)); } else { result = t.permissions.some(v => this.permissionGroups.includes(v)); } } // 用户自定义额外字段 if (typeof t.extraAll !== 'undefined') { result = result && t.extraAll; } if (typeof t.extraOne !== 'undefined') { result = result || t.extraOne; } } return t.except === true ? !result : result; } /** * 路由权限拦截 * @param url * @returns */ canAuthUrl(url) { return this.authPaths.has(url); } /** * 获取当前url对应是哪一个model_id * @param url * @returns */ getUrlModeId(url) { return this.authPaths.get(url); } getAuthPaths(value) { let reuslt = new Map(); value.forEach(authModel => { let model_id = authModel.model_id; reuslt.set(authModel.url, model_id); let stack = [...authModel.menu_list]; while (stack.length !== 0) { const item = stack.pop(); if (item) { reuslt.set(item.url, model_id); if (item.children) { for (let i = item.children.length - 1; i >= 0; i--) { stack.push(Object.assign({}, item.children[i])); } } } } }); return reuslt; } } LcAClService.decorators = [ { type: Injectable } ]; LcAClService.ctorParameters = () => []; class LcAClDirective { constructor(el, renderer, srv) { this.el = el; this.renderer = renderer; this.srv = srv; this.change$ = this.srv.change.pipe(filter(r => r != null)).subscribe(() => this.set(this._value)); } set lcAcl(value) { this.set(value); } set(value) { this._value = value; const CLS = 'lcAcl__hide'; const el = this.el.nativeElement; if (this.srv.can(this._value)) { this.renderer.removeClass(el, CLS); } else { this.renderer.addClass(el, CLS); } } ngOnDestroy() { this.change$.unsubscribe(); } } LcAClDirective.decorators = [ { type: Directive, args: [{ selector: '[lcAcl]', exportAs: 'lcAcl' },] } ]; LcAClDirective.ctorParameters = () => [ { type: ElementRef }, { type: Renderer2 }, { type: LcAClService } ]; LcAClDirective.propDecorators = { lcAcl: [{ type: Input, args: ['lcAcl',] }] }; class LcACLIfDirective { constructor(templateRef, srv, _viewContainer) { this.srv = srv; this._viewContainer = _viewContainer; this._thenTemplateRef = null; this._elseTemplateRef = null; this._thenViewRef = null; this._elseViewRef = null; this._except = false; this._change$ = this.srv.change.pipe(filter(r => r != null)).subscribe(() => this._updateView()); this._thenTemplateRef = templateRef; } set lcAclIf(value) { this._value = value; this._updateView(); } set lcAclIfThen(templateRef) { this._thenTemplateRef = templateRef; this._thenViewRef = null; this._updateView(); } set lcAclIfElse(templateRef) { this._elseTemplateRef = templateRef; this._elseViewRef = null; this._updateView(); } set except(value) { this._except = value != null && `${value}` !== 'false'; } get except() { return this._except; } _updateView() { const res = this.srv.can(this._value); if ((res && !this.except) || (!res && this.except)) { if (!this._thenViewRef) { this._viewContainer.clear(); this._elseViewRef = null; if (this._thenTemplateRef) { this._thenViewRef = this._viewContainer.createEmbeddedView(this._thenTemplateRef); } } } else { if (!this._elseViewRef) { this._viewContainer.clear(); this._thenViewRef = null; if (this._elseTemplateRef) { this._elseViewRef = this._viewContainer.createEmbeddedView(this._elseTemplateRef); } } } } ngOnDestroy() { this._change$.unsubscribe(); } } LcACLIfDirective.decorators = [ { type: Directive, args: [{ selector: '[lcAclIf]', exportAs: 'lcAclIf' },] } ]; LcACLIfDirective.ctorParameters = () => [ { type: TemplateRef }, { type: LcAClService }, { type: ViewContainerRef } ]; LcACLIfDirective.propDecorators = { lcAclIf: [{ type: Input }], lcAclIfThen: [{ type: Input }], lcAclIfElse: [{ type: Input }], except: [{ type: Input }] }; const COMPONENTS = [LcAClDirective, LcACLIfDirective]; class LcAclModule { // constructor(@Optional() @SkipSelf() parentModule?: LcAclModule) { // if (parentModule) { // throw new Error('LcAclModule is already loaded. Import it in the AppModule only'); // } // } static forRoot() { return { ngModule: LcAclModule, providers: [LcAClService], }; } } LcAclModule.decorators = [ { type: NgModule, args: [{ imports: [CommonModule], declarations: COMPONENTS, exports: COMPONENTS, },] } ]; const ACL_DEFAULT_CONFIG = { guard_url: `/auth/403`, }; /** * 目前用不到,startup.service.js 启动的时候已经判断当前的url是否是合法的 */ class LcAclGuard { constructor(srv, router) { this.srv = srv; this.router = router; } process(route, state) { if (this.srv.canAuthUrl(state.url)) { return true; } let guard_url = route.data.guard_url || '/auth/403'; this.router.navigateByUrl(guard_url); } canActivate(route, state) { return this.process(route, state); } // all children route canActivateChild(childRoute, state) { return this.process(childRoute, state); } } LcAclGuard.ɵprov = i0.ɵɵdefineInjectable({ factory: function LcAclGuard_Factory() { return new LcAclGuard(i0.ɵɵinject(LcAClService), i0.ɵɵinject(i2.Router)); }, token: LcAclGuard, providedIn: "root" }); LcAclGuard.decorators = [ { type: Injectable, args: [{ providedIn: 'root', },] } ]; LcAclGuard.ctorParameters = () => [ { type: LcAClService }, { type: Router } ]; /** * 提供一个方法方便查找菜单树中第一个最深层次的菜单url * @param menus * @returns */ function findFirstUrl(menus) { let firstMenu = menus[0]; let list = firstMenu.menu_list || firstMenu.children; if (!list || !list.length) { return firstMenu.url; } return findFirstUrl(list); } /** * 根据当前模块路径获取当前模块可以访问的第一个路由 * @param model_path * @returns */ function getModelFirstAuthPath(model_path, menu_storage_key = 'LCmenus') { const LCmenus = JSON.parse(localStorage.getItem(menu_storage_key) || '[]'); let result_path = '/auth/403'; if (LCmenus.length > 0) { LCmenus.forEach(model_item => { if (model_item.url === model_path) { result_path = findFirstUrl([model_item]); } }); } if (result_path !== '/auth/403') { let path = result_path.replace(new RegExp(model_path + '/'), ''); path && (result_path = path); } return result_path; } /** * 获取当前menu第一个授权的模块path * @param menu_storage_key */ function getMenuFirstAuthModel(menu_storage_key = 'LCmenus') { const LCmenus = JSON.parse(localStorage.getItem(menu_storage_key) || '[]'); let result_path = ''; if (LCmenus.length) { result_path = LCmenus[0].url; } return result_path; } /** * Generated bundle index. Do not edit. */ export { ACL_DEFAULT_CONFIG, LcACLIfDirective, LcAClDirective, LcAClService, LcAclGuard, LcAclModule, findFirstUrl, getMenuFirstAuthModel, getModelFirstAuthPath }; //# sourceMappingURL=acl.js.map