Estoy tratando de implementar un Angular Guard usando el paquete npm de Angular Social Login:
@Injectable({ providedIn: 'root', }) export class LoginGuard implements CanActivate { constructor(private router: Router, private authService: SocialAuthService) {} canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean> { console.log('guard'); return this.authService.authState.pipe( map((socialUser: SocialUser) => { console.log('map'); return !!socialUser; }), catchError((error) => { console.log(error); return of(false); }) ); } } Puedo ver que la guard se imprime en la consola. Sin embargo, no puedo ver el map impreso en la consola. ¿Por qué?
Si lo hago:
@Injectable({ providedIn: 'root', }) export class LoginGuard implements CanActivate { constructor(private router: Router, private authService: SocialAuthService) {} canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean> { console.log('guard'); return new Observable<boolean>((subscriber) => { console.log('subscriber'); subscriber.next(true); }); } } Puedo ver el subscriber que se imprime en la consola.
¿Qué estoy haciendo mal?
Quiero poder agregar este Guardia a una ruta. Si un usuario no ha iniciado sesión, sería redirigido a una página de inicio de sesión (sé que todavía no estoy implementando esa lógica; lo intenté y fallé porque parece que no obtengo un Observable con valores). Tenga en cuenta que estoy usando Google como proveedor para esto:
@NgModule({ declarations: [ AppComponent, IndexPageComponent, SearchPageComponent, InputKeywordsComponent, DisplayNewsListComponent, ], imports: [ BrowserModule, AppRoutingModule, ReactiveFormsModule, HttpClientModule, SocialLoginModule, ], providers: [ { provide: 'SocialAuthServiceConfig', useValue: { autoLogin: false, providers: [ { id: GoogleLoginProvider.PROVIDER_ID, provider: new GoogleLoginProvider( 'superVerySecret' ), }, ], } as SocialAuthServiceConfig, }, ], bootstrap: [AppComponent], }) export class AppModule {}Y el módulo de enrutamiento:
const routes: Routes = [ { path: '', component: IndexPageComponent }, { path: 'search', component: SearchPageComponent, canActivate: [LoginGuard] }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule], providers: [LoginGuard] }) export class AppRoutingModule {}PS1: Puedo iniciar sesión muy bien.
PS2:
Necesita una take(1) antes de su mapa, para obtener el valor más reciente de this.authService.authState es decir:
@Injectable({ providedIn: 'root', }) export class LoginGuard implements CanActivate { constructor(private router: Router, private authService: SocialAuthService) {} canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean> { console.log('guard'); return this.authService.authState.pipe( take(1), // <--- add this line map((socialUser: SocialUser) => { console.log('map'); return !!socialUser; }), catchError((error) => { console.log(error); return of(false); }) ); } }Felicitaciones a @msmiechowski por ayudarme a encontrar una solución en este problema de GitHub.
Mi solución:
// login.guard.ts @Injectable({ providedIn: 'root', }) export class LoginGuard implements CanActivate { constructor(private router: Router, private loginService: LoginService) {} canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): Observable<boolean> { if (this.loginService.checkAuthState()) { return of(true); } else { this.router.navigateByUrl('/'); return of(false); } } } // login.service.ts // ... checkAuthState(): boolean { let flag = false; this.authService.authState.subscribe({ next: (socialUser: SocialUser) => { if (socialUser) { flag = true; } }, error: (error) => { console.log(error); }, complete: () => { console.log('Complete!'); }, }); return flag; } // ...