Angular 社交登录(使用 Google)+ Angular 守卫

Angular Social Login (with Google) + Angular Guards

我正在尝试使用 Angular 社交登录 npm 包实现 Angular Guard:

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

我可以看到 guard 正在打印到控制台。但是,我看不到 map 打印到控制台。为什么?

如果我这样做:


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

我可以看到 subscriber 正在打印到控制台。

我做错了什么?

我希望能够将此 Guard 添加到路线中。如果用户未登录,它将被重定向到登录页面(我知道我还没有实现该逻辑;我已经尝试过但失败了,因为我似乎没有获得带有值的 Observable?)。请注意,我使用 Google 作为提供者:

@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 {}

以及路由模块:

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: 我可以正常登录

PS2:

您的地图前需要一个 take(1),以获得 this.authService.authState 的最新值,即:

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

感谢 @msmiechowski for helping me reaching a solution in this GitHub 问题。

我的解决方案:

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

// ...