Angular app permissions
Tags: angular, permissions
Published: 2023-03-27 21:26:03



This article is about the approach to frontend permissions based on simple library created in angular.

Let we imagine that we have simple block of code template e.g.
```html
<ul>
  <li>Apple</li>
  <li>Banana</li>
  <li>Strawberry</li>
</ul>
```

For some reason we want to prevent to display 'Apple' for specific user permission.

To be more precise we can create technically some simulation of permissions e.g.

```javascript
const permissions: Permission[] = [
  {
    name: 'SOME_SIMPLE_PERMISSION',
  },
  {
    name: 'FRUITS',
    subjects:[{
      name:'APPLE',
      accessType:['read']
    }]
  },
];

@Injectable()
export class FakeApiService {
  public getPermissions(): Observable<Permission[]> {
    return of(permissions);
  }
}
```

In the next step let we create some permission service:

```javascript
export type PermissionAccessType = 'create' | 'read' | 'update' | 'delete';

export interface Permission {
  name: string;
  subjects?: Array<Permission>;
  accessType?: Array<PermissionAccessType>;
}

@Injectable()
export class PermissinionService {
  private _permissions$: Observable<Array<Permission>>;
  private _permissionsEmitter$: BehaviorSubject<Array<Permission>> = new BehaviorSubject<Array<Permission>>([]);
  private _currentPermission$: Observable<Permission | undefined>;

  constructor() {
    this._permissions$ = this._permissionsEmitter$.asObservable();
  }

  public setPermissions(permissions: Array<Permission>): void {
    this._permissionsEmitter$.next(permissions);
  }

  public checkIfPermission(
    name: string,
    accessType?: PermissionAccessType[]
  ): this {
    this._currentPermission$ = this._permissions$.pipe(
      map((permissions: Permission[]) => {
        const permission: Permission | undefined = permissions.find(
          (permission: Permission) => permission.name === name
        );

        if (permission && accessType) {
          return this.checkAccessType(accessType, permission)
            ? permission
            : undefined;
        }

        return permission;
      })
    );

    return this;
  }

  public for(subjectName: string): this {
    this._currentPermission$ = this._currentPermission$.pipe(
      map((permission: Permission | undefined) =>
        permission
          ? permission.subjects?.find(
              (subject: Permission) => subject.name === subjectName
            )
          : undefined
      )
    );

    return this;
  }

  public withAccessType(accessType: PermissionAccessType[]): this {
    this._currentPermission$ = this._currentPermission$.pipe(
      map((permission: Permission | undefined) => {
        if (permission) {
          return this.checkAccessType(accessType, permission)
            ? permission
            : undefined;
        }

        return undefined;
      })
    );

    return this;
  }

  public exits(): Observable<boolean> {
    return this._currentPermission$.pipe(map(Boolean));
  }

  private checkAccessType(
    accessType: PermissionAccessType[],
    permission: Permission
  ): boolean {
    return accessType.every((accessType: PermissionAccessType) =>
      permission.accessType?.includes(accessType)
    );
  }
}
```

After do that we can simple use it for the component e.g.

```javascript
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
})
export class AppComponent implements OnInit {
  public canReadApple$: Observable<boolean>;

  constructor(private permissionService: PermissinionService) {}

  public ngOnInit(): void {
    this.canReadApple$ = this.permissionService
      .checkIfPermission('FRUITS')
      .for('APPLE')
      .withAccessType(['read'])
      .exits();
  }
}
```

And on the end let we back to our template (_app.component.html_), and let we use our permission logic:

```html
<ul>
  <li *ngIf="canReadApple$ | async">Apple</li>
  <li>Banana</li>
  <li>Strawberry</li>
</ul>
```

In the next article we can create some directive connected with our PermissinionService and use it without *ngIf condition c.d.n.


GitHub: https://github.com/p-rogulski/uic-auth