Загрузите разрешения перед загрузкой модуля, когда будет принят окончательный маршрут в URL - PullRequest
0 голосов
/ 30 марта 2020

Хорошо, у меня есть маршрут: site / dashboards / orders

  {
    path: 'dashboards',
    loadChildren: () => import('./dashboards/dashboards.module').then(m => m.DashboardsModule),
    canActivate: [AuthGuard, NgxPermissionsGuard],
    data: {
      permissions: {
        only: ['admin', 'dashboards'],
        redirectTo: 'homepage'
      }
    }
  }

В своем компоненте приложения я проверяю, аутентифицирован ли пользователь, и если да, получает роли из API и разрешает загрузку, используя NgxPermissions module

app.component.ts (в конструкторе):

constructor(private services) {
  this.checkAuth();
}

checkAuth() {
   apiService.checkAuth().subscribe((value: boolean) => {
     if (value) {
        // get roles with another api call
          apiService.getRoles().subscribe(roles => {
            this.permissionsService.loadPermissions(roles);
          });  
     }
   });
}

Я знаю, что это не лучший способ иметь подписку внутри другой подписки, но это не имеет значения прямо сейчас.

Если я захожу на сайт с первой страницы, проблема не существует, потому что:

  • go на сайт / домашнюю страницу => checkAuth () выполняется и имеет достаточно времени, чтобы получить результаты API => загрузить роли

  • перейти к инструментальным панелям / заказам => роли уже загружены с предыдущего шага (если я не наговиваюсь слишком быстро) и при маршрутизации go к пути «сводные панели» и проверке данных ТОЛЬКО с разрешениями [«admin», «сводные панели»], это позволит мне получить доступ к маршруту, поскольку роли существуют.

Но, если я попытаюсь получить прямой доступ к сайту / панелям / заказам:

  • app.component.ts - это первый загруженный компонент в Angular, поэтому будет вызываться метод checkAuth (). Но поскольку это наблюдаемое, перейдем к следующему действию (проверка прав доступа к данным маршрутизации) до его завершения. Поскольку роли не загружены, приложение перенаправит меня на «домашнюю страницу».

Как мне дождаться загрузки ролей, прежде чем получить доступ к маршрутизации и проверить разрешения?

Мне нужно только получить роли один раз (при первом обращении к приложению), а не для каждого модуля маршрутизации. Можно ли прослушивать наблюдаемые в модулях маршрутизации?

Короче, мне нужно загрузить роли перед маршрутами.

спасибо

1 Ответ

0 голосов
/ 30 марта 2020

Я нашел решение, я не знаю, является ли оно лучшим, но оно работает:

Отказ в NgxPermissionsGuard и создание еще одного защитника PermissionsGuard, который реализует CanActivate и отправляет роли и redirectTo в качестве параметров обоих защитников.

Маршрутизация:

{
    path: 'dashboards',
    loadChildren: () => import('./dashboards/dashboards.module').then(m => m.DashboardsModule),
    canActivate: [AuthGuard, PermissionsGuard],
    data: {
      roles: ['admin', 'dashboards'],
      redirectTo: 'homepage'
    }
  }

PermissionsGuard.ts:

export class PermissionsGuard implements CanActivate {
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    const routeRoles = next.data.roles as Array<string>;
    const redirectTo = next.data.redirectTo;

    const userName = localStorage.getItem('userName');
    return this.getRoles(userName, routeRoles, redirectTo);
  }

  getRoles(userName: string, routeRoles: string[], redirectTo: string) {
    let userRoles = [];
    const roles = this.permissionsService.getPermissions();
    for (const key in roles) {
      userRoles.push(key);
    }

    if (userRoles.length > 0) {
      return this.isInRole(userRoles, routeRoles, redirectTo);
    } else {
      // api call, get user roles 
      return this.isInRole(apiResult, routeRoles, redirectTo);
    }
  }

  isInRole(userRoles: string[], routeRoles: string[], redirectTo: string) {
    // let canAccessRoute = false;
    // check if routeRoles contain any element of userRoles

    if (canAccessRoute) {
      return true;
    } else {
      this.router.navigateByUrl(redirectTo);
    }
  }
}

Оба охранника (AuthGuard и PermissionsGuard) должны вернуть true , чтобы предоставить пользователю доступ к маршруту. Некоторые данные являются результатом обещаний, поэтому необходимо использовать методы возврата.

...