2016-11-04 23 views
15

我正在使用Angular 2.1.2。Angular2 - 如何最好地處理過期的身份驗證令牌?

我有一個身份驗證令牌(使用angular2-jwt),如果它過期,我的webApi調用失敗,出現401錯誤。我正在尋找一個解決方案,用戶不會丟失任何輸入數據。

我可以抓住這個401並打開登錄模式。用戶然後登錄,模式消失,並且他們看到他們的輸入屏幕。但是,失敗的請求顯示錯誤,因此我需要重新處理請求。如果是路由器導航,則尚未加載初始數據。

我可以重新加載頁面,但如果我router.navigate到同一頁面它似乎並沒有實際重新加載頁面。我不想在單頁面應用上完成整頁重新加載。有沒有辦法強制router.navigate運行,即使它是當前頁面?

重新導航仍然是一個問題,因爲我會失去任何未保存的新輸入數據。

理想情況下,請求只會「暫停」直到用戶從模式登錄。我還沒有找到實現這一點的方法。

任何想法? 是否有最佳做法?

+0

關於與終極版處理應用程序的狀態是什麼? –

+1

如果您綁定到共享服務的數據,那麼在重新導航後它不會丟失。類似於Redux的建議。 –

+0

即使頁面重新加載,是否需要保存? – Maxime

回答

2

好,重裝很簡單:(<any>window).location.reload(true);

這是好主意,顯示登錄/密碼彈出,並允許用戶繼續工作,如果他能提供密碼,如果用戶點擊取消只是重定向到登錄頁面。

還有連接問題,超時,服務器錯誤。問題在於使用Angular 2 Http模塊和rxjs難以可靠地實現正確的處理。就我個人而言,我放棄使用Http模塊,因爲它的錯誤處理設計不好,並且實現了我自己的http模塊,它允許配置錯誤處理和透明重試。

1

後,我做的一個登錄,並獲得令牌(在我的情況下,在60分鐘內到期),我設置了一個時間間隔,每分鐘檢查59分鐘是否已經過去。如果是,那麼我打開一個登錄對話框。

然而,這個想法是登錄對話框不是一個路由,而只是一個疊加層,打開在用戶碰巧在的任何屏幕之上(因此我把登錄組件放在應用程序根目錄的html中組件,並使用observable從應用程序中的任何位置調用登錄對話框)。

當用戶正確地重新登錄時,我關閉登錄對話框,並且用戶在他們不得不重新登錄之前使用他們正在使用的任何屏幕愉快地走動。

我不知道這是否是「最佳做法」,但它適用於您描述的情況。讓我知道,我可以貼上代碼。

5

通常我會提供一個HttpService我自己,而不是直接使用Http。因此,根據您的要求,我可以在發送任何實際的HTTP請求之前提供自己的get()方法來鏈接身份驗證。

這裏是服務:

@Injectable() 
class HttpService { 
    constructor(private http: Http, private auth: Authentication) {} 

    public get(url: string): Observable<Response> { 
    return this.auth.authenticate().flatMap(authenticated => { 
     if (authenticated) { 
     return this.http.get(url); 
     } 
     else { 
     return Observable.throw('Unable to re-authenticate'); 
     } 
    }); 
    } 
} 

這裏是調用該服務的組件:

@Component({ 
    selector: 'my-app', 
    template: `<h1>Hello {{name}}</h1> 
    <button (click)="doSomething()">Do Something</button> 

    <div [hidden]="!auth.showModal"> 
    <p>Do you confirm to log in?</p> 
    <button (click)="yes()">Yes</button><button (click)="no()">No</button> 
    </div> 
    `, 
}) 
export class AppComponent { 
    name = 'Angular'; 

    constructor(private httpSvc: HttpService, public auth: Authentication) {} 

    ngOnInit() { 
    } 

    doSomething() { 
    let a = this.httpSvc.get('hello.json').subscribe(() => { 
     alert('Data retrieved!'); 
    }, err => { 
     alert(err); 
    }); 
    } 

    yes() { 
    this.auth.confirm.emit(true); 
    } 

    no() { 
    this.auth.confirm.emit(false); 
    } 
} 

通過鏈接可觀測量,所述Authentication服務確定是否中斷的正常流動,以顯示模式(儘管目前只與App組件共存,但它當然可以單獨實現)。一旦從對話中收到了肯定的答案,服務就可以恢復流程。

class Authentication { 
    public needsAuthentication = true; 
    public showModal = false; 
    public confirm = new EventEmitter<boolean>(); 

    public authenticate(): Observable<boolean> { 
    // do something to make sure authentication token works correctly 
    if (this.needsAuthentication) { 
     this.showModal = true; 
     return Observable.create(observer => { 
     this.confirm.subscribe(r => { 
      this.showModal = false; 
      this.needsAuthentication = !r; 
      observer.next(r); 
      observer.complete(); 
     }); 
     }); 
    } 
    else { 
     return Observable.of(true); 
    } 
    } 
} 

我在這裏有一個完整的現場示例。

http://plnkr.co/edit/C129guNJvri5hbGZGsHp?open=app%2Fapp.component.ts&p=preview