2

我正在尝试使用 Angular Social Login 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正在打印到控制台。

我究竟做错了什么?

我希望能够将此警卫添加到路线中。如果用户未登录,它将被重定向到登录页面(我知道我还没有实现该逻辑;我已经尝试过但失败了,因为我似乎没有得到带有值的 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:

  • @角/核心@12.2.13
  • @rxjs@6.6.7
  • angularx-social-login@4.0.1
4

2 回答 2

2

您需要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);
      })
    );
  }
}
于 2021-11-30T10:30:59.083 回答
0

感谢 @msmiechowski帮助我在这个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;
}

// ...
于 2021-12-09T11:35:28.197 回答