typescript - Hur kan du använda Angulars canActivate för att negatera resultatet av en guard?


Från Angular-dokumentationen om canActivate verkar det som att du endast kan använda canActivate-vakter för att tillåta att fortsätta till en rutt om canActivate-funktionen slutligen returnerar true.

Finns det något sätt att säga, "fortsätt endast till denna rutt om canActivate-klassen utvärderas till false"?

Till exempel, för att inte tillåta inloggade användare att besöka inloggningssidan, försökte jag detta men det fungerade inte:

export const routes: Route[] = [
    { path: 'log-in', component: LoginComponent, canActivate: [ !UserLoggedInGuard ] },

Jag fick detta fel i konsolen:

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!

Svar #1

Det intressanta i din fråga är formuleringen:

Finns det något sätt att säga, "fortsätt endast till denna rutt om canActivate-klassen utvärderas till false" ?

Och hur du uttryckte den "intuitiva" lösningen:

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

Vilket i princip säger att du behöver förneka resultatet av UserLoggedInGuard@canActivate

Låt oss överväga följande implementering av UserLoggedInGuard:

@Injectable()
export class UserLoggedInGuard implements CanActivate {
   constructor(private _authService: AuthService) {}

   canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
        return this._authService.isLoggedIn();
    }
} 

Nästa, låt oss titta på lösningen som föreslogs av @Mike

@Injectable()
export class NegateUserLoggedInGuard implements CanActivate {    
    constructor(private _authService: AuthService) {}

   canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
        return !this._authService.isLoggedIn();
    }
}

Nu är tillvägagångssättet okej, men det är tätt kopplat till den (interna) implementeringen av UserLoggedInGuard. Om implementeringen av UserLoggedInGuard@canActivate av någon anledning ändras, kommer NegateUserLoggedInGuard att gå sönder.

Hur kan vi undvika det? Enkelt, missbruka beroendeinjektion:

@Injectable()
export class NegateUserLoggedInGuard implements CanActivate {    
  constructor(private _userLoggedInGuard: UserLoggedInGuard) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
     return !this._userLoggedInGuard.canActivate(route,state);
  }
}

Nu gör detta exakt vad du uttryckte med

canActivate: [ !UserLoggedInGuard ]

Och det bästa:

  • Det är inte tätt kopplat till den interna implementeringen av UserLoggedInGuard
  • Kan utökas för att manipulera resultatet av mer än en Guard-klass

Svar #2

Jag hade ett liknande problem - jag ville skapa en inloggningssida som bara var åtkomlig om man inte var autentiserad och en instrumentpanel som bara var åtkomlig om man var autentiserad (och automatiskt omdirigera användaren till rätt sida). Jag löste det genom att göra själva skyddet känsligt för både inloggning och rutt:

Rutterna:

const appRoutes: Routes = [
  { path: 'login', component: LoginComponent, canActivate: [AuthGuard] },
  { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] },

Vakten:

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;
      }
    }
  }
}

Relaterade artiklar