Угловая навигация 5 отменена после возвращения охранника - PullRequest
0 голосов
/ 27 апреля 2018

У меня есть три маршрута, один из них защищен охранником

app.routing-module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LoginComponent } from './modules/auth/login/login.component';
import { DashboardComponent } from './modules/dashboard/dashboard.component';
import { CustomersComponent } from './modules/customers/customers.component';

import { AuthGuard } from './shared/guards/auth.guard';


const routes: Routes = [
  {
    path: '',
    redirectTo: 'home',
    pathMatch: 'full'
  },
  { path: 'home', component: DashboardComponent, canActivate: [AuthGuard] },
  { path: 'login', component: LoginComponent },
  { path: 'customers', component: CustomersComponent },
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule],
  providers: [AuthGuard]
})
export class AppRoutingModule { }

Страж получает, если пользователь авторизован из хранилища ngrx, и возвращает Наблюдаемое, чтобы разрешить или не активировать маршрут.

import { Injectable } from '@angular/core';
import {
  CanActivate,
  ActivatedRouteSnapshot,
  RouterStateSnapshot,
  Router
} from '@angular/router';
import { Observable } from 'rxjs/Observable';
import { catchError, map, switchMap, filter, take } from 'rxjs/operators';
import { of } from 'rxjs/observable/of';
import { Store } from '@ngrx/store';

import { getUserAuth } from '../../store/reducers';


@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private store: Store<any>, private router: Router) { }

  getUserAuth(): Observable<any> {
    return this.store.select(getUserAuth).pipe(
      filter((data: any) => data),
      take(1)
    );
  }

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> | Promise<boolean> | boolean {
    return this.getUserAuth().pipe(
      switchMap(() => of(true)),
      catchError(() => of(false))
    );
  }
}

При переключении между двумя «общедоступными» маршрутами навигация работает нормально, но после попытки доступа к защищенному маршруту и ​​отмены (пользователь не авторизован) навигация отменяется, и ни один из маршрутов не может быть принят. С другой стороны, если пользователь вошел в систему, навигация работает нормально, и три маршрута доступны.

Если я возвращаю простой Observable.of (false) в методе canActivate, защищенный маршрут не может быть принят, но навигация по другим маршрутам все еще работает

canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean {
    return Observable.of(false);
}

Почему навигация отменена?

EDIT

Я забыл сказать, что я использую @ ngrx / router-store, поэтому мой app.module выглядит так:

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    AppRoutingModule,
    CoreModule,
    StoreModule.forRoot(rootReducers, {metaReducers}),
    StoreRouterConnectingModule.forRoot({
      stateKey: 'router' // name of reducer key
    }),
    StoreDevtoolsModule.instrument({ maxAge: 25 }),
    EffectsModule.forRoot(rootEffects),
    AuthModule,
    DashboardModule,
    CustomersModule
  ],
  providers: [{ provide: RouterStateSerializer, useClass: CustomSerializer }],
  bootstrap: [AppComponent]
})

1 Ответ

0 голосов
/ 28 апреля 2018

Проблема лежит здесь:

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private store: Store<any>, private router: Router) { }

  getUserAuth(): Observable<any> {
    return this.store.select(getUserAuth).pipe(
      filter((data: any) => data),
      ^^^^^^
      take(1)
    );
  }

AuthGuard приостанавливает навигацию до тех пор, пока Observable не разрешится до true или false. Поскольку вы фильтруете любые значения falsy null, Observable не будет ничего выдавать, когда пользователь не аутентифицирован. Вы должны сопоставить значения с true / false вместо:

return this.store.select(getUserAuth).pipe(
  map((data: any) => !!data),
  ^^^^^^^^^^^^^^^^^^^^^^^^^
  take(1)
);
...