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

我目前正在开发 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);
  }
  ...
}

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

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

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

最佳答案

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

改为设置路由器防护,由 Angular API 调用 CanActivate。这将在路由激活时调用,重定向可能在路由组件加载之前发生故障,并且只会被调用一次。使用它来调用 service.isAuthenticated

login.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;
    }

在你的路由定义中

export const routes: Routes = [
    { path: '', component: SomeComponent },
    { path: 'main', component: ProtectedComponent, canActivate: [LoginGuard] }
]

在任何情况下都不应该被调用 1000 次。我猜你的组件或注入(inject)树中正在进行一些循环。

https://stackoverflow.com/questions/44005163/

相关文章:

Python 3.6.1 - 权限错误 : [Errno 13] Permission denied

reactjs - React router v4 历史记录,有没有办法获取您导航的网址?

Scala - 查找列表当前元素的确切索引

html - 如何在 Rails 中为 datetime_field_tag 设置默认值

wpf - 在 WPF 中串联静态资源

reactjs - 改变列标题高度

node.js - config.js 文件的 Typescript 版本

amazon-ec2 - 由于超时,无法从 EC2 实例连接到 SQS

c# - 在 SortedSet 上调用 ToArray()/ToList() 是否保证返回排

swagger - 在响应文本中显示换行符