2017-05-16 74 views
0

我目前正在開發一個Angular 4應用程序。如何正確檢查用戶是否在Angular4中進行身份驗證?

應用程序使用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的教程,但我認爲這不可能是預期的行爲,因爲它會影響應用程序的性能。

什麼可能是經常被稱爲認證的事實的原因?我是否必須實施一個定時器,在指定時間後定期執行檢查,還是必須實施觀察員?我的代碼中是否有明顯的錯誤?

回答

0

最後,我找到了原因。

我的導航組件使用主機偵聽器@HostListener('mouseover', ['$event'])實現了轉換效果。我不小心將主機偵聽器添加到窗口對象。出於這個原因,每次我移動鼠標時,主機監聽器都被觸發。由於我的導航模板包含*ngIf="auth.isAuthenticated()"以顯示一些導航項目,以防萬一用戶通過身份驗證,因此多次激發了isAuthenticated

3

調用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。我猜你的組件或注入樹中有一些循環。

相關問題