Как вы можете использовать Angular canActivate, чтобы отрицать результат защиты?
Из Angular документации на canActivate
, похоже, вы можете использовать только защитные устройства canActivate
, чтобы разрешить переход на маршрут, если функция canActivate
в конечном итоге возвращает true
.
Можно ли сказать, "только переходите к этому маршруту, если класс canActivate
оценивается как false
"?
Например, чтобы не разрешать входам пользователей на страницу входа в систему, я пробовал это, но это не сработало:
export const routes: Route[] = [
{ path: 'log-in', component: LoginComponent, canActivate: [ !UserLoggedInGuard ] },
Я получил эту ошибку в консоли:
ERROR Error: Uncaught (in promise): Error: StaticInjectorError[false]:
StaticInjectorError[false]:
NullInjectorError: No provider for false!
Error: StaticInjectorError[false]:
StaticInjectorError[false]:
NullInjectorError: No provider for false!
Ответы
Ответ 1
Интересным в вашем вопросе является формулировка:
Есть ли способ сказать: "Переходите к этому маршруту, если класс canActivate оценивается как false"
И как вы выразили "интуитивное" решение:
{ path: 'log-in', component: LoginComponent, canActivate: [ !UserLoggedInGuard ] },
Что в основном говорит, вам нужно negate
результат [email protected]
Рассмотрим следующую реализацию UserLoggedInGuard
:
@Injectable()
export class UserLoggedInGuard implements CanActivate {
constructor(private _authService: AuthService) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
return this._authService.isLoggedIn();
}
}
Далее, рассмотрим решение, предложенное @Mike
@Injectable()
export class NegateUserLoggedInGuard implements CanActivate {
constructor(private _authService: AuthService) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
return !this._authService.isLoggedIn();
}
}
Теперь подход одобрен, но тесно связан с (внутренней) реализацией UserLoggedInGuard
. Если по какой-то причине реализация [email protected]
изменится, NegateUserLoggedInGuard
сломается.
Как мы можем избежать этого? Простая инъекция зависимости от злоупотребления:
@Injectable()
export class NegateUserLoggedInGuard implements CanActivate {
constructor(private _userLoggedInGuard: UserLoggedInGuard) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
return !this._userLoggedInGuard.canActivate(route,state);
}
}
Теперь это делает точно то, что вы выразили с помощью
canActivate: [ !UserLoggedInGuard ]
И лучшая часть:
- Он не тесно связан с внутренней реализацией
UserLoggedInGuard
- Может быть расширен для управления результатом более чем одного класса
Guard
Ответ 2
Размышляя о вашей проблеме, одним из решений может быть реализация защиты маршрута, которая делает логику обратным.
import { MyService } from "./myservice.service";
import { CanActivate, RouterStateSnapshot, ActivatedRouteSnapshot } from "@angular/router";
import { Injectable } from "@angular/core";
@Injectable()
export class MyGuard implements CanActivate {
constructor(private myService: MyService) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
return this.myService.isNotLoggedIn(); //if user not logged in this is true
}
}
Ответ 3
У меня была похожая проблема - я хотел создать страницу входа, которая была бы доступна только в том случае, если она не прошла проверку подлинности, а панель мониторинга - только в том случае, если вы прошли проверку подлинности (и перенаправить пользователя на соответствующую страницу автоматически). Я решил это, сделав сам логин охранника + маршрут чувствительным:
Маршруты:
const appRoutes: Routes = [
{ path: 'login', component: LoginComponent, canActivate: [AuthGuard] },
{ path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] },
Страж:
export class AuthGuard implements CanActivate {
private login: UrlTree;
private dash: UrlTree;
constructor(private authSvc: AuthenticationService, private router: Router ) {
this.login = this.router.parseUrl('login');
this.dash = this.router.parseUrl('dashboard');
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | UrlTree {
if (this.authSvc.isSignedIn()) {
if (route.routeConfig.path === 'login') {
return this.dash;
} else {
return true;
}
} else {
if (route.routeConfig.path === 'login') {
return true;
} else {
return this.login;
}
}
}
}