All Projects → chihab → ngx-access

chihab / ngx-access

Licence: other
Add access control to your components using hierarchical configuration with logical expressions.

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language
HTML
75241 projects
CSS
56736 projects

Projects that are alternatives of or similar to ngx-access

Ngx Permissions
Permission and roles based access control for your angular(angular 2,4,5,6,7,9+) applications(AOT, lazy modules compatible
Stars: ✭ 749 (+3466.67%)
Mutual labels:  permissions, roles, access, access-control
Accesscontrol
Role and Attribute based Access Control for Node.js
Stars: ✭ 1,723 (+8104.76%)
Mutual labels:  permissions, roles, access-control
Unix Permissions
Swiss Army knife for Unix permissions
Stars: ✭ 106 (+404.76%)
Mutual labels:  permissions, access, access-control
nova-permissions
Add Permissions based authorization for your Nova installation via User-based Roles and Permissions. Roles are defined in the database whereas Permissions are defined in the code base.
Stars: ✭ 115 (+447.62%)
Mutual labels:  permissions, roles, access-control
Monarchy
Hierarchical access management system with advanced roles inheritance. 🦋
Stars: ✭ 48 (+128.57%)
Mutual labels:  roles, access, access-control
Think Authz
An authorization library that supports access control models like ACL, RBAC, ABAC in ThinkPHP 6.0 .
Stars: ✭ 155 (+638.1%)
Mutual labels:  permissions, roles, access-control
Sentinel
A framework agnostic authentication & authorization system.
Stars: ✭ 1,354 (+6347.62%)
Mutual labels:  permissions, roles
Rbac.dev
A collection of good practices and tools for Kubernetes RBAC
Stars: ✭ 115 (+447.62%)
Mutual labels:  permissions, access-control
Laravel Auth
A powerful authentication, authorization and verification package built on top of Laravel. It provides developers with Role Based Access Control, Two-Factor Authentication, Social Authentication, and much more, compatible Laravel’s standard API and fully featured out of the box.
Stars: ✭ 128 (+509.52%)
Mutual labels:  permissions, roles
Laravel Authz
An authorization library that supports access control models like ACL, RBAC, ABAC in Laravel.
Stars: ✭ 136 (+547.62%)
Mutual labels:  permissions, access-control
Django Access
Django-Access - the application introducing dynamic evaluation-based instance-level (row-level) access rights control for Django
Stars: ✭ 47 (+123.81%)
Mutual labels:  permissions, access
Laravel Governor
Manage authorization with granular role-based permissions in your Laravel Apps.
Stars: ✭ 131 (+523.81%)
Mutual labels:  permissions, roles
Maravel Permissions
Because in the Maravelous univer every user deserves super power
Stars: ✭ 139 (+561.9%)
Mutual labels:  permissions, roles
Vakt
Attribute-based access control (ABAC) SDK for Python
Stars: ✭ 92 (+338.1%)
Mutual labels:  permissions, access-control
Brandenburg
Laravel Authentication Package
Stars: ✭ 79 (+276.19%)
Mutual labels:  permissions, roles
Laratrust
Handle roles and permissions in your Laravel application
Stars: ✭ 1,799 (+8466.67%)
Mutual labels:  permissions, roles
Adonis Acl
demo app: https://github.com/enniel/adonis-acl-blog-demo
Stars: ✭ 195 (+828.57%)
Mutual labels:  permissions, roles
Vue Gates
🔒 A Vue.js & Nuxt.js plugin that allows you to use roles and permissions in your components or DOM elements, also compatible as middleware and methods.
Stars: ✭ 184 (+776.19%)
Mutual labels:  permissions, roles
rbac
Simple RBAC/ACL for Laravel 8 caching and permission groups.
Stars: ✭ 43 (+104.76%)
Mutual labels:  permissions, roles
Pundit Elixir
Simple authorization helpers for Elixir stucts, like Ruby's Pundit
Stars: ✭ 17 (-19.05%)
Mutual labels:  permissions, access-control

🔑 ngx-access 🔑


Npm version MIT PRs

ngx-access is a non-opnionated access control library for Angular.

Features

  • No more endless "ngIf statements" in your components
  • Define your access control as logical expressions
  • Usage in template and code
  • Display parent only if one of the children is displayed
  • Load your access control configuration from a file or from your server
  • Provide your custom reactive strategy to verify if the user has a given access
  • Compatible and tested against mainstream Angular versions

Table of Contents

In a Nutshell

Basic usage

<app-sidebar *ngxAccess="'ADMIN'"></app-sidebar>

The app-sidebar component is displayed only if the user has 'ADMIN' access.


Usage with logical expressions

<app-salaries *ngxAccess="'ADMIN | HR'; else unauthorized"></app-salaries>

<ng-template #unauthorized>
  You do not have enough permissions to display this section.
</ng-template>

The app-salaries component is displayed only if the user has ADMIN OR HR access.

Define your Access strategy

The ADMIN and HR access are evaluated using your custom strategy

import { AccessStrategy } from "ngx-access";

@Injectable()
export class RoleAccessStrategy implements AccessStrategy {
  constructor(private userService: UserService) {}

  check(role: string): boolean {
    return this.userService
      .getRoles()
      .some((userAccess) => userAccess === role);
  }
}

You have full control on how Access Control should be verified, ngx-access doesn't differentiate between User, Role and Permissions based access controls. They're all access controls, you put whatever access control logic you want in your AccessStrategy service.

ngx-access is simply the glue between the logical expression you put in your template and the custom AccessStrategy you define.

The Access strategy can be reactive.

There are predefined strategies provided for some common use cases though. (WIP 🚧)

Installation

Install ngx-access

npm install --save ngx-access

Compatibility

ngx-access version >= 1.4.2 and above has verified compatibility with the following Angular versions.

Angular version ngx-access version
11.x
10.x
9.x
8.x
7.x
6.x

If the version you are using is not listed, please raise an issue in our GitHub repository.

Access strategy

To define your custom access strategy

1. Define the strategy

import { AccessStrategy } from "ngx-access";

@Injectable()
export class PermissionAccessStrategy implements AccessStrategy {
  constructor(private userService: UserService) {}

  // You have full control on access control logic
  check(persmission: string): boolean {
    return this.userService
      .getPermissions()
      .some((userPermission) => userPermission === persmission);
  }
}

You can implement a reactive strategy by returning an Observable<boolean>.

import { AccessStrategy } from "ngx-access";

@Injectable()
export class PermissionAccessStrategy implements AccessStrategy {
  constructor(private userService: UserService) {}

  // You have full control on access control logic
  check(persmission: string): Observable<boolean> {
    return this.userService
      .getPermissions()
      .pipe(
        map((userPermissions: string[]) =>
          userPermissions.some(
            (userPermission) => userPermission === persmission
          )
        )
      );
  }
}

2. Provide the strategy

import { AccessStrategy } from "ngx-access";
import { PermissionAccessStrategy } from "./core/access.service";

@NgModule({
  providers: [{ provide: AccessStrategy, useClass: PermissionAccessStrategy }],
})
export class AppModule {}

Usage in template

Static access control

<input
  *ngxAccess="'CanUpdateAll | (CanUpdateUser & CanUpdateUserPassword)'"
  type="password"
/>

The input element is displayed only if the user has CanUpdateAll access OR both CanUpdateUser And CanUpdateUserEmail access.

If user has CanUpdateAll access, CanUpdateUser and CanUpdateUserEmail access will not be evaluated.

Parent access control

By putting *ngxAccess in an view, its display will depend on the display of its childre (no limit on depth). If one child is display, meaning that the child has a given access or has an else statement, the parent will also be displayed.

Below, the form (including h1) will be displayed only if the user has one of the access in the input elements beneath.

<form *ngxAccess>
  <h1>Update User Form</h1>
  <input *ngxAccess="'CanUpdateUserAvatar'" />
  <input *ngxAccess="'CanUpdateUserName'" />
  <input *ngxAccess="'CanUpdateUserAge'" />
  <input *ngxAccess="'CanUpdateUserPassword'" />
</form>

Logical Expression

Type Description Evaluation
& Access1 & Access2 true if user has Access1 AND Access2.
| Access1 | Access2 true if user has Access1 OR Access2
&/| Access1 & (Access2 | Access3) true if user has Access1 AND (Access2 OR Access3)

Usage in code

AccessService

You can use AccessService to check if a user is granted an access.

import { Component, OnInit } from "@angular/core";
import { AccessService } from "ngx-access";

@Component({
  selector: "app-main",
  templateUrl: "./component.html",
  styleUrls: ["./component.css"],
})
export class MainComponent {
  constructor(private accessService: AccessService) {}

  submit() {
    if (this.accessService.check("ADMIN | HR")) {
      // Send ADMIN | HRspecific Payload to backend
    }
  }
}

AccessGuard

You can use AccessGuard as a guard deciding if a route can be activated / loaded depending on the experssion/path you provide.

  {
    path: "admin",
    component: AdminComponent,
    canActivate: [AccessGuard],
    data: {
      access: "ADMIN", // or access configuration ":Home.Admin.Read"
      redirectTo: "/unauthorized",
      // if no 'ADMIN' access, guard refirects to '/unauthorized'
    },
  },

Full example

import { AccessGuard, AccessModule, AccessStrategy } from "ngx-access";

@NgModule({
  imports: [
    AccessModule.forRoot({
      redirectTo: "/forbidden", // Default path redirected to from Guard when the access is revoked
    }),
    RouterModule.forRoot([
      {
        path: "profile",
        component: ProfileComponent,
        canActivate: [AccessGuard],
        data: {
          access: "ADMIN",
          // if no 'ADMIN' access, guard refirects to '/forbidden' defined at module level
        },
      },
      {
        path: "salaries",
        loadChildren: () =>
          import("./salaries/salaries.module").then((m) => m.SalariesModule),
        canLoad: [AccessGuard],
        data: {
          access: "ADMIN | HR",
          // if no 'ADMIN' or 'HR' access, guard refirects to '/not-found'
          redirectTo: "/not-found",
        },
      },
      { path: "forbidden", component: UnauthorizedComponent },
      { path: "not-found", component: NotFoundComponent },
    ]),
  ],
  providers: [{ provide: AccessStrategy, useClass: MyAccessStrategy }],
})
export class AppModule {}

Configuration Based Access Control

We can define access controls using external access configuration. This is useful when we want to maintain the access:

First we setup the Access Control configuration by mapping unique IDs with the Access Control Logical Expression to evaluate.

{
  "UserForm": "CanReadUser | CanUpdateUser",
  "UserMenu": "CanListUsers"
}

In the template we provide the Access Control ID

<input *ngxAccess="':UserForm'" />
<!-- is equivalent to -->
<input *ngxAccess="'CanReadUser | CanUpdateUser'" />

Access Control Configuration

We can use flat configuration that maps IDs with Access Control expressions

export const ACCESS_CONFIGURATION: AccessConfiguration = {
  UserForm: "CanReadUser | CanUpdateUser",
  UserMenu: "CanListUsers",
};

Or a Hierarchical configuration for better readbility

export const ACCESS_CONFIGURATION: AccessConfiguration = {
  User: {
    Form: {
      Email: {
        Read: "CanReadUserEmail",
        Update: "CanReadUserEmail & CanUpdateUserEmail",
      },
      Password: {
        Update: "CanUpdateUserPassword",
      },
    },
  },
};

which can be used in the template like this:

<input *ngxAccess="':User.Form.Email.Read'" />
<input type="password" *ngxAccess="':User.Form.Password'" />

app-user-form component below is displayed only if the user has at least one of the Update access defined beneath the User.Form access path, namely: (CanReadUserEmail and CanUpdateUserPassword) or CanUpdateUserAddress access.

<app-user-form *ngxAccess="':User.Form.Update'"></app-user-form>
<!-- is equivalent to -->
<app-user-form
  *ngxAccess="'(CanReadUserEmail & CanUpdateUserEmail) | CanUpdateUserAddress'"
></app-user-form>

Module Configuration

The access configuration can be set in a module:

import { ACCESS_CONFIGURATION } from "./access-configuration";

@NgModule({
  imports: [
    AccessModule.forRoot({
      access: ACCESS_CONFIGURATION,
    }),
  ],
  providers: [{ provide: AccessStrategy, useClass: RoleAccessStrategy }],
})
export class AppModule {}

Service Configuration

The access configuration can be in a service:

import { ACCESS_CONFIGURATION } from "./access-configuration";

import { Component } from "@angular/core";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
})
export class AppComponent {
  constructor(private accessService: AccessService) {}
  ngOnInit() {
    this.accessService.setConfiguration(ACCESS_CONFIGURATION);
  }
}

Logical Expressions

You can use logical expression on your access ids

<app-user *ngxAccess=":('UserForm' | 'UserMenu')"></app-user>

Server access configuration

You can get the access configuration from your server at startup

import { APP_INITIALIZER } from "@angular/core";

export function loadServerConf(
  accessService: AccessService,
  http: HttpClient
): () => Promise<void> {
  return () => {
    // You can have a specific endpoint to load the access configuration specific to the user
    const apiConf$ = this.http
      .get<AccessModuleConfiguration>("/api/me/access")
      .pipe(catchError((_) => of({})));

    // You can load the configuration as a static asset
    const staticConf$ = this.http
      .get<AccessModuleConfiguration>("/assets/access.json")
      .pipe(catchError((_) => of({})));

    return serverConf$ // or staticConf$
      .toPromise()
      .then((configuration: AccessConfiguration) => {
        accessService.setConfiguration(configuration);
      });
  };
}

@NgModule({
  providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: loadServerConf,
      deps: [AccessService, HttpClient],
      multi: true,
    },
  ],
})
export class AppModule {}

External access configuration

You can import the access configuration as JSON. Note that the configuration will be part of your application bundle.

1. Enable JSON imports in tsconfig.json

{
  "compilerOptions": {
    "declaration": false,
    "resolveJsonModule": true,
    "esModuleInterop": true
  }
}

2. Create access.json file

{
  "UserForm": "CanReadUser | CanUpdateUser",
  "UserMenu": "CanListUsers"
}

3. Import access.json file

import access from "./src/assets/access.json";

@NgModule({
  imports: [
    AccessModule.forRoot({
      access,
    }),
  ],
})
export class AppModule {}

Credits

LEP by NimitzDEV

License

MIT © Chihab Otmani

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].