Недавно появилась задача в одном достаточно крупном проекте ограничивать UI и функционал пользователей, в зависимости от их ролей. К этому моменту приложение уже разрослось на 100+ компонент, и это при том что основные базовые компоненты вынесены в отдельную репу и ставятся пакетом. То есть примерно в каждом из 100+, вероятно придется вносить некоторые правки, связанные с правами доступа.
Первой мыслью было пройтись по всем компонентам, заинжектить через DI UserService, прокинуть в шаблон контекст пользователя, и там с этим как-то разбираться. Однако, на счастье, я не успел этим заняться, так как нашел другое, как мне кажется более удачное решение.
exportAs
Я подумал о том, как можно сразу в шаблонах получить userContext, без необходимости инжектировать сервис или токен с пользователем в контроллерах компонент. На счастье вспомнилась весьма удобная штучка: свойство директив (ну и компонент, как наследников, естественно) — exportAs.
Что же дает exportAs?
Вот что нам сообщает документация:
exportAs: Определяет имя, которое может быть использовано в шаблоне для назначения этой директивы переменной.
Как же этим воспользоваться?
Допустим, у нас есть сервис, который авторизовался и хранит данные о пользователе.
@Injectable({ providedIn: 'root', }) export class UserService { private user$: User; set user(user: User) { this.user$ = user; } get user() { return this.user$; } constructor( private _http: HttpClientWrapperService ) { } ... }
И есть класс, описывающий пользователя
export class User { id: number; name: string; claims: Claim[]; get roles() { return this.claims?.map(_ => _.code); } get isAdmin() { return this.roles?.indexOf('ADMIN') >= 0; } get isUser() { return this.isAdmin || this.roles?.indexOf('USER') >= 0; } get isGuest() { return this.isAdmin || this.isUser || this.roles?.indexOf('GUEST') >= 0; } ... }
Что нам нужно — создать директиву, которая будет иметь доступ к пользователю, например такую:
import {Directive} from '@angular/core'; import {UserService} from '../../service/user.service'; @Directive({ selector: '[appUserContext]', exportAs: 'userContext' }) export class UserContextDirective { get user() { return this._user?.user; } constructor(private _user: UserService) { } }
И использовать ее по надобности в шаблонах приложения. Например так, если добавлять у удалять объект может только администратор.
<div class="column content-block" appUserContext #user="userContext"> <app-toolbar> <ng-container *ngIf="user.user?.isAdmin"> <button app-button (click)="add()"> <app-icon [name]="'add'"></teta-icon> </button> <button app-button (click)="delete()"> <teta-icon [name]="'delete'"></teta-icon> </button> </ng-container> </app-toolbar> </div>
Также данная функция может использована для получения доступа к директивам и компонентам в шаблоне, без необходимости использовать ViewChild там, где для этого нет большой необходимости.
Спасибо за внимание, надеюсь эта информация окажется для вас полезной и сэкономит кому-то время.
ссылка на оригинал статьи https://habr.com/ru/post/661213/
Добавить комментарий