#angular #asynchronous #routes
Вопрос:
Я хочу запретить обычным пользователям доступ /players
, /scores
и, если они попытаются, он должен перенаправить их на /home
. Доступ к другим маршрутам разрешен только администраторам. Моя проблема в том, что данные, указывающие, является ли пользователь администратором или нет, поступают из асинхронной функции. В файле guard: this.getService.getUserRoles()
возвращает роли пользователя(администратор-это роль).
// to check wether user is admin or not
async isAdmin(): Promise<boolean> {
if (JSON.stringify(await this.getService.getUserRoles()).includes("admin")) {
return true;
}
return false;
}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot) {
const path: string = route.paramMap.get('path');
if (!(this.isAdmin())) {
if (path === "players" || path === "scores") {
// router: Router
this.router.navigate(['/home']);
return false;
}
}
return true;
}
Я добавил canActivate:[RoutesGuard]
оба маршрута в модуль маршрутизации приложений.
Есть идеи, что случилось?
Комментарии:
1. можете ли вы напечатать путь в console.log
Ответ №1:
Я использую этого охранника
import { Injectable } from '@angular/core';
import { HttpErrorResponse } from '@angular/common/http';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { AdvancedRouter } from '@mintplayer/ng-router';
import { AccountService } from '../../services/account/account.service';
@Injectable({
providedIn: 'root'
})
export class IsInRoleGuard implements CanActivate {
constructor(
private accountService: AccountService,
private router: AdvancedRouter,
) {
}
canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
return this.accountService.currentRoles().then((roles) => {
let routeRoles = <string[]>next.data.roles;
let intersect = roles.filter(r => routeRoles.indexOf(r) > -1);
return intersect.length > 0;
}).catch((error: HttpErrorResponse) => {
this.router.navigate(['/account', 'login'], {
queryParams: {
return: state.url
}
});
return false;
});
}
}
Это модуль маршрутизации, в котором я внедряю охрану:
const routes: Routes = [
{ path: '', loadChildren: () => import('./list/list.module').then(m => m.ListModule) },
{ path: ':id/:name', loadChildren: () => import('./show/show.module').then(m => m.ShowModule) },
{ path: 'create', loadChildren: () => import('./create/create.module').then(m => m.CreateModule), canActivate: [IsInRoleGuard], canDeactivate: [HasChangesGuard], data: { roles: ['Blogger'] } },
{ path: ':id/:name/edit', loadChildren: () => import('./edit/edit.module').then(m => m.EditModule), canActivate: [IsInRoleGuard], canDeactivate: [HasChangesGuard], data: { roles: ['Blogger'] } },
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class BlogRoutingModule { }
Вы можете буквально просто вернуть Promise<boolean>
из своего canActivate
метода.
Ответ №2:
Вы должны вернуть наблюдаемое из canActivate guard, иначе Angular не будет ждать завершения вызова API и выполнения других операций.
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {
return this.getService.getUserRoles()
.pipe(
map(resp => {
if (allowed) return true;
else {
// return false and navigate to home
this.router.navigateByUrl(`home`);
return false;
}
})
);
}