web-dev-qa-db-ja.com

AngularのcanActivateを使用してガードの結果を無効にする方法を教えてください。

canActivateのAngularドキュメント から、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!
14
CodyBugstein

あなたの質問で興味深いのは定式化です:

canActivateクラスがfalseと評価された場合にのみこのルートに進むと言う方法はありますか?

そして、「直感的な」ソリューションをどのように表現したか:

{ path: 'log-in', component: LoginComponent, canActivate: [ !UserLoggedInGuard ] },

基本的に言って、あなたはnegateの結果をUserLoggedInGuard@canActivate

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の(内部)実装と密接に結びついています。何らかの理由でUserLoggedInGuard@canActivate変更、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クラスの結果を操作するために展開できます
10
Jota.Toledo

問題について考えると、1つの解決策は、論理を逆に行うルートガードを実装することです。

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
    }
}
2
Mike Tung

同様の問題がありました。認証されていない場合にのみアクセス可能なログインページを作成し、認証されている場合にのみダッシュボードにアクセスできるようにしたいと考えています(ユーザーを適切なものに自動的にリダイレクトします)。ガード自体をログイン+ルートに依存させることで解決しました。

ルート:

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;
      }
    }
  }
}
0
Jim ReesPotter