如何在 Angular4 中正确检查用户是否经过身份验证?

Mic*_*fer 3 authentication auth0 angular

我目前正在开发 Angular 4 应用程序。

该应用程序使用 Auth0 进行身份验证,其语法与其他身份验证服务的语法非常相似。

身份验证的代码如下所示:

// auth.services.ts

@Injectable()
export class Auth {
  public lock = new Auth0Lock(myConfig.clientID, myConfig.domain, myConfig.lock);
  public userProfile: any;
  public idToken: string;
  public signUpIncomplete: boolean;

  // Configure Auth0
  private auth0 = new Auth0.WebAuth({
    domain: myConfig.domain,
    clientID: myConfig.clientID,
    redirectUri: myConfig.redirectUri,
    responseType: myConfig.responseType
  });

  // Create a stream of logged in status to communicate throughout app
  private loggedIn: boolean;
  private loggedIn$ = new BehaviorSubject<boolean>(this.loggedIn);

  constructor(private router: Router, private http: Http) {
    // Set userProfile attribute of already saved profile
    this.userProfile = JSON.parse(localStorage.getItem('profile'));
  }

  public isAuthenticated(): boolean {
    // Check whether the id_token is expired or not
    console.log("isAuthenticated");
    return tokenNotExpired('id_token');
  }

  public login(username?: string, password?: string): Promise<any> {
    if (!username && !password) {
      return;
    }
    return this.processLogin(username, password);
  }

  public logout() {
    // Remove tokens and profile and update login status subject
    localStorage.removeItem('token');
    localStorage.removeItem('id_token');
    localStorage.removeItem('profile');
    this.idToken = '';
    this.userProfile = null;
    this.setLoggedIn(false);

    // Go back to the home rout
    this.router.navigate(['/']);
  }

  public loginWithWidget(): void {
    this.lock.show();
  }

  // Call this method in app.component
  // if using path-based routing <== WE ARE USING PATH BASED ROUTING
  public handleAuth(): void {
    // When Auth0 hash parsed, get profile
    this.auth0.parseHash({}, (err, authResult) => {
      if (authResult && authResult.accessToken && authResult.idToken) {
        // window.location.hash = '';
        this._getProfile(authResult);
        this.router.navigate(['/']);
      } else if (err) {
        this.router.navigate(['/']);
        console.error(`Error: ${err.error}`);
      }
    });
  }

  private setLoggedIn(value: boolean) {
    // Update login status subject
    this.loggedIn$.next(value);
    this.loggedIn = value;
  }

  private _getProfile(authResult) {
    // Use access token to retrieve user's profile and set session
    // const lock2 = new Auth0Lock(myConfig.clientID, myConfig.domain, myConfig.lock)
    const idToken = authResult.id_token || authResult.idToken;
    this.lock.getProfile(idToken, (error, profile) => {
      if (error) {
        // Handle error
        console.error(error.error);
        return;
      }
      // Save session data and update login status subject
      this._setSession(authResult, profile);
      if (!this.checkUserHasRole(profile)) {
        this.router.navigate(['/signup/complete']);
      }
    });
  }

  private _setSession(authResult, profile) {
    // Save session data and update login status subject
    localStorage.setItem('token', authResult.access_token || authResult.accessToken);
    localStorage.setItem('id_token', authResult.id_token || authResult.idToken);
    localStorage.setItem('profile', JSON.stringify(profile));
    this.idToken = authResult.id_token || authResult.idToken;
    this.setLoggedIn(true);
    this.userProfile = profile;
    this.checkUserHasRole(profile);
  }

  private processLogin(username?: string, password?: string): Promise<any> {
    const options = {
      client_id: myConfig.clientID,
      connection: postConfig.body.connection,
      grant_type: 'password',
      username,
      password,
      scope: myConfig.scope
    };
    const headers = new Headers();
    headers.append('content-type', 'application/json');
    const reqOpts = new RequestOptions({
      method: RequestMethod.Post,
      url: postConfig.urlLogin,
      headers,
      body: options
    });
    return this.http.post(postConfig.urlLogin, options, reqOpts)
      .toPromise()
      .then(this.extractData)
      .then((data) => { this._getProfile(data); })
      .catch(this.handleLoginError);
  }
  ...
}
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是该isAuthenticated方法在页面加载时被调用超过 1000 次。此外,每次我在窗口对象中移动鼠标时都会调用它。

尽管我一步步遵循了 Auth0 的教程,但我认为这不是预期的行为,因为它将会并且已经影响了应用程序的性能。

isAuthenticated 被频繁调用的原因可能是什么?我是否必须实现一个计时器,在指定时间后定期进行检查,或者我是否必须实现一个观察者?我的代码中是否有任何明显的错误?

joh*_*667 5

调用如此多次的原因isAuthenticated取决于调用它的组件,而这里没有。isAuthenticated在此服务中从未被调用过一次。

相反,设置一个路由器防护,CanActivate由 Angular API 调用。这将在路由激活时调用,并且在加载路由组件之前可能会在失败时发生重定向,并且只会调用一次。用它来打电话service.isAuthenticated

登录.guard.ts

import { Injectable } from '@angular/core';
import { Router, CanActivate } from '@angular/router';
import { Auth } from './auth.service';

@Injectable()
export class LoginGuard implements CanActivate {
    constructor(public auth: Auth, protected router: Router) { }

    canActivate() {
        if (!this.auth.isAuthenticated()) {
            this.router.navigate(['/']);
            return false;
        }
        return true;
    }
Run Code Online (Sandbox Code Playgroud)

在您的路线定义中

export const routes: Routes = [
    { path: '', component: SomeComponent },
    { path: 'main', component: ProtectedComponent, canActivate: [LoginGuard] }
]
Run Code Online (Sandbox Code Playgroud)

无论如何,它不应该被调用数千次。我猜测您的组件或注入树中正在发生一些循环。