Angular Firebase Guards, блокировка маршрутизации с конкретными ролями - PullRequest
0 голосов
/ 02 октября 2019

Привет Angular Developers,

Пожалуйста, мне нужна ваша помощь, мне нужно заблокировать маршрутизацию с определенными ролями, Это мой документ с профилями:

enter image description here

Мои угловые защитники возвращаются и объект с профилями: {admin: true, current: false}

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from '../services/auth.service';
import { map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})

export class RoleGuard implements CanActivate {

  constructor(
    public authService: AuthService,
    public router: Router
  ) { }

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<any> | boolean {

    return this.authService.getAuthWithProfile().pipe(
      map((data) => {
        const roles = data.roles;
        return roles; // This returns   {admin: true, current: false}
      })
    );

   }
  }

Вопрос в том, как реализовать защиту для ролей в угловой маршрутизации, например:

{ path: 'tasks', component: TasksComponent, canActivate: [RoleGuard] },

1 Ответ

1 голос
/ 02 октября 2019

Один из подходов - использование data свойства Route . Вы можете прикрепить пользовательские значения к любому маршруту. В вашем примере вы можете создать свойство с именем roles, которое можно использовать в вашем canActivate(). В следующем примере массив ролей добавляется к маршруту для TasksComponent. В охране мы можем извлечь roles из next.data.roles, а затем проверить, что роли, возвращаемые из Firebase, присутствуют и активны:

Маршрут:

{
  path: 'tasks',
  component: TasksComponent,
  data: {
    roles: ['admin', 'subscriber']
  }
  canActivate: [RoleGuard]
}

Охрана:

canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | boolean {
  const routeRoles = next.data && next.data.roles; // ['admin', 'subscriber']

  return this.authService.getAuthWithProfile().pipe(
    map((data) => {
      const roles = data.roles; // { admin: true, current: false }
      const activeRoles = Object.entries(roles).filter(([role, isActive]) => isActive).map(([role, isActive]) => role); // ['admin']

      return routeRoles.some(routeRole => activeRoles.includes(routeRole)); // true
    })
  );

  }
}

data.roles на маршруте не обязательно должен быть массив, вместо этого он может быть объектом, и вы можете подходить к проверке существования активированного маршрута любым удобным для вас способом. Например, если есть только одна роль:

{
  path: 'tasks',
  component: TasksComponent,
  data: {
    role: 'admin'
  }
  canActivate: [RoleGuard]
}

canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> | boolean {
  const routeRole = next.data && next.data.role; // 'admin'

  return this.authService.getAuthWithProfile().pipe(
    map((data) => {
      const roles = data.roles; // { admin: true, current: false }
      const activeRoles = Object.entries(roles).filter(([role, isActive]) => isActive).map(([role, isActive]) => role); // ['admin']

      return routeRoles.includes(routeRole); // true
    })
  );

  }
}

Надеюсь, это поможет!

...