0

我有个问题。所以,我想在 Angular 中创建一个路由保护,如果用户登录,则不允许用户访问登录页面。如果来自 AuthService 的 BehaviourSubject 发出一个新的用户对象,我会检查他是否登录,但是当我在搜索栏中输入登录页面的 URL,主题发出的用户对象变为空。你知道为什么会这样吗?

@Injectable({
  providedIn: 'root'
})
export class LoggedInGuard implements CanActivate {

  constructor(private authService: AuthService, private router: Router){}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
      return this.authService.user$.pipe(map(user => {
        // check if the user object is empty
        const isAuth = !(!!Object.keys(user).length);
        console.log(isAuth) 
        if(isAuth) {
          return true;
        }

        // navigate to /books if user is logged in
        return this.router.createUrlTree(['/books']);
      }));
  }
  
}

这是我的 AuthService 逻辑:

export class AuthService {
  private baseUsersUrl =
    environment.firebase.databaseURL + MAIN_API_ENDPOINTS.users;

  private userSource = new BehaviorSubject<User>(<User>{});
  user$ = this.userSource.asObservable();
  
  tokenExpirationTimer!: any;

  constructor(private httpClient: HttpClient,private afAuth: AngularFireAuth, private router: Router) { }

  login(email: string, password: string){
    return this.httpClient.post<AuthResponseData>(MAIN_API_ENDPOINTS.login,{
      email: email,
      password: password,
      returnSecureToken: true
    }).pipe(
      catchError(errorResponse => {
        console.log(errorResponse);
        let errorMessage = 'An unknown error occured!';

        if(!errorResponse.error || !errorResponse.error.error) {
          return throwError(errorMessage);
        } else {
          errorMessage = 'Email or password is incorrect'
        }

        return throwError(errorMessage);
      }),
      tap((resData) => {
        this.saveUserData(email, resData.localId, resData.idToken, +resData.expiresIn);
      }),
    );
  }

  saveUserData(email: string, localId: string, idToken: string, expiresIn: number) {
    const expirationDate = new Date(new Date().getTime() + expiresIn * 1000); 
    const currentUser: User = {
      email,
      id: localId,
      token: idToken,
      tokenExpirationDate: expirationDate
    };

    //token will expire in 1h
    this.autoLogout(expiresIn * 1000);
    document.cookie = 'token' + '=' + idToken;
  }

  autoLogin() {
    const idToken = document.cookie.split('=')[1];
    if(!idToken) {
      return;
    }

    this.getUserData(idToken).subscribe((user) => {
      this.saveUserData(user.users[0].email, user.users[0].localId, idToken, 100);   
    })
  }

  getUserData(idToken: string) {
    return this.httpClient.post<any>(
      MAIN_API_ENDPOINTS.userData,
      {idToken: idToken});     
    }

我以这种方式将这个路由守卫添加到路由中:

const routes: Routes = [
  {
    path: 'login',
    component: LoginComponent,
    canActivate: [LoggedInGuard]
  }]
4

1 回答 1

0

每当在浏览器的搜索栏中输入路线时,角度应用程序都会以干净的状态引导自己。您实际上需要做的是尝试autoLogin()在您的代码到达LoggedInGuard. 每当在 Angular 应用程序中遇到路线时canActivate,如果路线上存在路线,则首先运行。我相信您在执行完其逻辑AuthService后运行,因此无法执行登录路由验证并让路由打开。如果您想尝试,也可以在登录页面时尝试刷新浏览器窗口。你将面临同样的情况。LoggedInGuardLoggedInGuard

于 2021-07-14T09:10:32.877 回答