☰
Nebular Security 模块安装指南:从 npm 安装到 forRoot 注册
2026/9/26 2:49:59 网站建设 项目流程
  • 前端
  • UI组件

【免费下载链接】nebular

:boom: Customizable Angular UI Library based on Eva Design System :new_moon_with_face::sparkles:Dark Mode

项目地址:https://gitcode.com/gh_mirrors/ne/nebular
点击查看免费下载

本文以 Nebular 组件库中的@nebular/security模块为主线,完整讲解其安装、导入与注册流程,并深入NbSecurityModule.forRoot()的底层实现,说明如何同时配置 ACL 访问控制规则与RoleProvider角色提供器,帮助你在 Angular 应用中快速落地"基于角色的前端访问控制"。读完本文,你将掌握从零安装 Nebular Security、注册模块、配置权限规则,并在模板与服务中使用*nbIsGranted指令与NbAccessChecker完成资源级授权判断的完整实战方案。

安装前的准备

@nebular/security以 npm 包的形式独立分发,不依赖@nebular/auth(认证)或@nebular/theme(主题)模块,但官方建议将三者配合使用:Nebular Auth 负责"你是谁"(authenticate),Nebular Security 负责"你能做什么"(authorize)。在动手安装前,请确认你的项目已满足以下前提:

  • 项目基于 Angular 框架,且已配置好 npm 包管理器;
  • 如果你使用的是 ngx-admin starter kit,那么 Security 模块已经预置在项目中,无需重复安装,可直接跳到「导入并注册模块」一节。

从当前仓库中@nebular/security的 package.json 可以看到其声明信息:包名@nebular/security,版本17.0.0,MIT 协议,核心依赖仅为tslib,sideEffects: false(可安全参与 tree-shaking)。其peerDependencies要求@angular/common、@angular/core、@angular/router及rxjs@^6.5.3 || ^7.4.0,因此你的 Angular 应用本身必须满足这些对等依赖版本要求。

第一步:npm 安装 Security 模块

执行以下命令即可安装:

npm i @nebular/security

安装完成后,node_modules/@nebular/security下即为编译好的库产物。该包仅包含 Security 模块自身(ACL 服务、访问检查服务、角色提供器抽象类与条件指令),不含主题样式,因此在styles.scss中不需要额外引入其样式文件。

第二步:导入模块

在需要使用该模块的文件(通常是根模块app.module.ts)顶部导入NbSecurityModule:

import { NbSecurityModule } from '@nebular/security';

从仓库的 public_api.ts 可以看到,该包公开导出:

  • security.options——NbAclOptions、NbAccessControl、NbAclRole等类型定义;
  • security.module——NbSecurityModule;
  • services/acl.service——NbAclService;
  • services/access-checker.service——NbAccessChecker;
  • services/role.provider——NbRoleProvider抽象类;
  • directives/is-granted.directive——NbIsGrantedDirective。

第三步:在根模块中注册

在根模块的imports数组中调用静态方法NbSecurityModule.forRoot():

@NgModule({ imports: [ // ... 其他模块 NbSecurityModule.forRoot(), ], }) export class AppModule { }

这一步完成之后,Nebular Security 就已经安装并启用,可以进行 ACL 配置了。

forRoot() 背后发生了什么

NbSecurityModule.forRoot()并不是一个空操作。查看源码 security.module.ts:

static forRoot(nbSecurityOptions?: NbAclOptions): ModuleWithProviders<NbSecurityModule> { return { ngModule: NbSecurityModule, providers: [ { provide: NB_SECURITY_OPTIONS_TOKEN, useValue: nbSecurityOptions }, NbAclService, NbAccessChecker, ], }; }

从中可以看出三个关键点:

  1. forRoot()接受可选的NbAclOptions参数,并以NB_SECURITY_OPTIONS_TOKEN(InjectionToken)的形式注入到应用级 providers 中,这就是后续 ACL 配置的入口;
  2. 它在应用根级别提供了NbAclService(ACL 存储与判定服务)和NbAccessChecker(访问检查服务),意味着整个应用共享同一份权限状态;
  3. 模块本身还声明并导出了NbIsGrantedDirective指令(见同一文件的declarations与exports),因此只要导入了NbSecurityModule,模板中就能直接使用*nbIsGranted。

需要留意的是,forRoot()与模块体的职责分离:模块体部分(CommonModule导入、指令声明/导出)在模块被 import 时即生效,而forRoot()返回的 providers 则只在根模块生效,这正是"安装一次、全局可用"的设计意图。

第四步(可选):配置 ACL 访问控制规则

forRoot()的配置参数类型NbAclOptions定义于 security.options.ts:

export interface NbAclRole { parent?: string, [permission: string]: string|string[]|undefined, } export interface NbAccessControl { [role: string]: NbAclRole, } export interface NbAclOptions { accessControl?: NbAccessControl, }

即:一个角色(role)可以声明一个可选的parent父角色,以及若干"权限 → 资源(单个字符串或字符串数组)"的映射。把配置传入forRoot():

@NgModule({ imports: [ // ... NbSecurityModule.forRoot({ accessControl: { guest: { view: ['news', 'comments'], }, user: { parent: 'guest', create: 'comments', }, moderator: { parent: 'user', create: 'news', remove: '*', }, }, }), ], }) export class AppModule { }

这个配置表达了三层权限模型:

角色父角色权限与资源含义
guest无view: ['news', 'comments']访客只能查看新闻与评论
userguestcreate: 'comments'登录用户继承访客全部权限,并可创建评论
moderatorusercreate: 'news'、remove: '*'版主继承用户权限,并可创建新闻、删除任意资源

配置中的*是通配资源占位符,表示该权限对任意资源生效(例如moderator的remove: '*'意味着可以删除news和comments)。

父角色继承与通配符的底层行为

这些规则由NbAclService落地执行,源码位于 acl.service.ts:

  • NbAclService内部以private state: NbAccessControl保存整张 ACL 表,构造时若检测到settings.accessControl存在,会立即调用setAccessControl()完成初始化(见constructor,L26-L30);
  • 每个角色通过register(role, parent, abilities)注册,权限通过allow(role, permission, resource)逐条写入(L50-L82);
  • 判定核心是can(role, permission, resource)方法(L91-L97):它先递归检查父角色是否被授予该权限,再调用exactCan做精确匹配。换言之,子角色自动继承父角色的全部权限,无需重复声明;
  • exactCan(L115-L118)的判定逻辑是:资源精确命中权限列表,或者权限列表中包含ANY_RESOURCE(即'*'通配符)即视为授权通过。

同时注意一个使用限制:can()方法(validateResource,L109-L113)禁止以'*'作为被检查的资源,因为通配符只应出现在授权配置中,作为检查请求时会被抛出异常(cannot use empty or bulk '*' resource placeholder with 'can' method)。

这些行为在仓库测试 acl.spec.ts 中有直接印证,例如 L152-L173 验证了"子角色继承父角色权限":admin注册为user的子角色后,aclService.can('admin', 'remove', 'users')为true,而独立的user与guest对此资源均为false;L237-L257 则验证了"父角色后续新增的权限同样能被子角色感知"。

第五步:提供 RoleProvider 确定当前用户角色

ACL 表只回答了"角色 X 对资源 Y 有什么权限",还需要一个机制告诉 Nebular"当前登录用户是谁"。这就是NbRoleProvider的职责。

NbRoleProvider是一个抽象类,定义于 role.provider.ts:

export abstract class NbRoleProvider { abstract getRole(): Observable<string|string[]>; }

它的唯一方法getRole()返回一个Observable<string | string[]>,可以返回单个角色,也可以返回多个角色(例如一个用户同时拥有多个角色)。

方式一:最简单的硬编码提供方式

直接在根模块的providers中以useValue提供一个对象字面量实现:

// ... import { of as observableOf } from 'rxjs/observable/of'; import { NbSecurityModule, NbRoleProvider } from '@nebular/security'; @NgModule({ imports: [ // ... NbSecurityModule.forRoot({ // ... ACL 配置 }), ], providers: [ // ... { provide: NbRoleProvider, useValue: { getRole: () => { return observableOf('guest'); }, }, }, ], }) export class AppModule { }

这种方式适合原型开发或写死角色的场景。它的优势是与认证流程完全解耦——无论你的登录体系是什么,只要提供一个返回角色的getRole()即可,这为后续接入任意认证方案留下了充分灵活性。

方式二:从认证 Token 中动态读取角色(推荐)

真实应用中角色是动态的。假设你的项目已经基于 Nebular Auth 的 JWT 方案完成了认证,可以创建一个独立的role.provider.ts服务,从用户 token 中提取角色:

import { Injectable } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { map } from 'rxjs/operators/map'; import { NbAuthService, NbAuthJWTToken } from '@nebular/auth'; import { NbRoleProvider } from '@nebular/security'; @Injectable() export class RoleProvider implements NbRoleProvider { constructor(private authService: NbAuthService) { } getRole(): Observable<string> { return this.authService.onTokenChange() .pipe( map((token: NbAuthJWTToken) => { return token.isValid() ? token.getPayload()['role'] : 'guest'; }), ); } }

这段代码订阅onTokenChange()可观察对象——每当认证状态变化(登录、登出、token 刷新)都会产生一个新 token——然后从 token payload 中读取role字段;若 token 无效则回退为默认的guest角色。为简化示例,这里假设 token payload 中始终存在role字段;如果你的 JWT 结构不同,按实际字段名调整即可。

如果你的项目没有使用 Nebular Auth 也没关系,官方文档明确说明:可以把这个方法替换为从你自己的任何服务中获取用户角色。

然后在模块中注册这个类:

// ... import { RoleProvider } from './role.provider'; import { NbSecurityModule, NbRoleProvider } from '@nebular/security'; @NgModule({ imports: [ // ... NbSecurityModule.forRoot({ // ... ACL 配置 }), ], providers: [ // ... { provide: NbRoleProvider, useClass: RoleProvider }, ], }) export class AppModule { }

注意NbAccessChecker的构造签名(见 access-checker.service.ts)同时注入了NbRoleProvider与NbAclService,因此一旦你覆盖了NbRoleProvider的实现,全应用的权限判定就会自动切换到你提供的角色来源,无需改动其他代码。

在应用中使用安全规则

配置完成后,就可以在应用各处启用权限控制。假设你有一个"发表评论"(Post Comment)按钮,只对拥有create+comments权限的登录用户显示,访客不可见。

方式一:使用 *nbIsGranted 指令(模板方案)

Nebular Security 提供了*nbIsGranted条件指令,它的工作方式与*ngIf类似,根据用户角色决定模板块的显示/隐藏。查看源码 is-granted.directive.ts,该指令的输入是一个[permission, resource]二元组,内部通过NbAccessChecker.isGranted()订阅判定结果,为true时用ViewContainerRef.createEmbeddedView渲染模板,为false时clear()移除视图,并随组件销毁自动取消订阅。

使用示例:

@Component({ // ... template: ` <button *nbIsGranted="['create', 'comments']" >Post Comment</button> `, }) export class CommentFormComponent { // ... }

只需要把permission和resource以元组形式传给指令即可。

方式二:使用 NbAccessChecker 服务(编程方案)

对于更复杂的场景(路由守卫、服务内部、动态 UI 逻辑),可以直接注入NbAccessChecker服务。它的isGranted(permission, resource)方法返回Observable<boolean>:

import { Component } from '@angular/core'; import { NbAccessChecker } from '@nebular/security'; @Component({ // ... }) export class CommentFormComponent { constructor(public accessChecker: NbAccessChecker) { } }

在模板中配合async管道使用:

@Component({ // ... template: ` <button *ngIf="accessChecker.isGranted('create', 'comments') | async" >Post Comment</button> `, }) export class CommentFormComponent { // ... }

从 access-checker.service.ts 的实现可以看到,isGranted内部先取当前角色(支持string | string[],统一归一化为数组),再对每个角色调用NbAclService.can(),只要任一角色被授权即返回true。由于它订阅的是可观察的角色流,当应用运行期间认证状态发生变化(如用户登出)时,按钮会自动隐藏,无需手动刷新页面。

同样的isGranted方法可以在应用的任意位置调用,包括路由守卫(CanActivate)与各类服务中,从而以统一、透明、可配置的方式管理用户对各类资源的访问。

重要提醒:前端 ACL 的边界

需要特别强调的是,Nebular Security 属于前端 ACL 方案(见 Security 模块介绍):它解决的是"界面上该给谁看什么、该允许谁操作什么"的体验与导航问题,不能替代服务端的权限校验。攻击者可以绕过前端直接调用后端接口,因此必须在后端重复实现同样的安全规则。前端 ACL + 后端校验双管齐下,才是完整的安全方案。

相关阅读

  • Roles & Permissions:ACL 配置与使用:本文中 ACL 配置示例的完整展开,涵盖三种角色(guest/user/moderator)、三种权限(view/create/remove)与两种资源(news/comments)的完整演示;
  • Security 模块总体介绍:了解 ACL、RoleProvider、NbAccessChecker、*nbIsGranted各组成部分的定位,以及尚在规划中的 Security Decorator;
  • 模块源码与测试:security.module.ts、acl.service.ts、access-checker.service.ts、is-granted.directive.ts、acl.spec.ts。
  • 前端
  • UI组件

【免费下载链接】nebular

:boom: Customizable Angular UI Library based on Eva Design System :new_moon_with_face::sparkles:Dark Mode

项目地址:https://gitcode.com/gh_mirrors/ne/nebular
点击查看免费下载
上一篇:华硕笔记本性能优化终极指南:3步用G-Helper替代臃肿的奥创中心
下一篇:Pixelle-Video:零门槛AI视频生成工具终极指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询