2017-05-15 9 views
12

Jaki jest najlepszy sposób obsługi niejawnego przepływu oddzwaniania w Angular 4? Chcę, żeby Strażnik czekał, aż użytkownik zostanie przekierowany z powrotem z tokenem i jest przechowywany, zanim Strażnik zwróci wartość true lub false. Odbieram dostęp Odmowa dostępu na kilka sekund, zanim nastąpi przekierowanie z powrotem, aby sprawdzić token. Czy istnieje lepszy sposób na obsłużenie AuthGuarda niż to, co robię, więc nie otrzymuję odmowy dostępu przed zakończeniem uwierzytelniania?Ograniczenie wywołania i ostrzeżenia o routerach Angular 4 Implicit Flow

Jak sprawić, aby router czekał na przekierowanie?

AppComponent

ngOnInit() {  

     //if there is a hash then the user is being redirected from the AuthServer with url params 
     if (window.location.hash && !this.authService.isUserLoggedIn()) {  

      //check the url hash 
      this.authService.authorizeCallback(); 

     } 
     else if (!this.authService.isUserLoggedIn()) {   

      //try to authorize user if they aren't login 
      this.authService.tryAuthorize();  

    }  
} 

AuthSerivce

tryAuthorize() { 
     //redirect to open id connect /authorize endpoint 
     window.location.href = this.authConfigService.getSignInEndpoint(); 
    } 

    authorizeCallback() {  

     let hash = window.location.hash.substr(1); 

     let result: any = hash.split('&').reduce(function (result: any, item: string) { 
      let parts = item.split('='); 
      result[parts[0]] = parts[1]; 
      return result; 
     }, {}); 


     if (result.error && result.error == 'access_denied') { 
      this.navigationService.AccessDenied(); 
     } 
     else { 

      this.validateToken(result); 
     } 
    } 


    isUserLoggedIn(): boolean {  
     let token = this.getAccessToken(); 

     //check if there is a token  
     if(token === undefined || token === null || token.trim() === '') 
     { 
      //no token or token is expired; 
      return false; 
     } 

     return true; 
    } 


    getAccessToken(): string {    

     let token = <string>this.storageService.get(this.accessTokenKey); 


     if(token === undefined || token === null || token.trim() === '') 
     { 
      return ''; 
     } 

     return token; 
    } 

    resetAuthToken() { 
     this.storageService.store(this.accessTokenKey, ''); 
    } 

    validateToken(tokenResults: any) {   

     //TODO: add other validations   

     //reset the token 
     this.resetAuthToken(); 

     if (tokenResults && tokenResults.access_token) { 

      //store the token 
      this.storageService.store(this.accessTokenKey, tokenResults.access_token); 

      //navigate to clear the query string parameters 
      this.navigationService.Home(); 

     } 
     else { 
      //navigate to Access Denied 
      this.navigationService.AccessDenied(); 
     } 

    } 
} 

AuthGuard

canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot){ 

    var hasAccess = this.authService.isUserLoggedIn();   

    if(!hasAccess) 
    { 
     this.naviationService.AccessDenied(); 
     return false; 
    } 
    return true;  
    } 

Odpowiedz

5

Jeśli chcesz, aby strażnik czekał na asynchroniczne zadanie, musisz zmienić AuthService, aby zwrócić obserwowalną i emitowaną wartość, która jest potrzebna w asynchronicznym zadaniu, które chcesz poczekać, w twoim przypadku jego reduce(). Potem dokonaj subskrypcji w straży. W ten sposób możesz sprawić, że strażnik będzie czekał na każde asynchroniczne zadanie.

AuthGuard

canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot){ 

    this.authService.isUserLoggedIn().map(logged => { 
     if (logged) { 
      return true; 
     } else { 
      this.naviationService.AccessDenied(); 
      return false; 
     } 
    }).catch(() => { 
     this.naviationService.AccessDenied(); 
     return Observable.of(false); 
    }); 
    } 
} 

część AuthService

isUserLoggedIn(): Observable<boolean> { 
    return new Observable((observer) => { 
     let hash = window.location.hash.substr(1); 

     let result: any = hash.split('&').reduce(function (result: any, item: string) { 
     let parts = item.split('='); 
     result[parts[0]] = parts[1]; 

     if (result.error && result.error == 'access_denied') { 
      observer.next(false); 
      observer.complete(); 
     } 
     else { 
      this.validateToken(result); 
     } 
     let token = this.getAccessToken(); 

     //check if there is a token  
     if(token === undefined || token === null || token.trim() === '') 
     { 
      //no token or token is expired; 
      observer.next(false); 
      observer.complete(); 
     } 

     observer.next(true); 
     observer.complete(); 
     }, {}); 
    }); 
} 
+0

Wydaje się, że działa dobrze, ale mam inny problem, który prawdopodobnie może być związany z używaniem urządzeń Observables. Gdy próbuję użyć usługi iniekcyjnej wewnątrz Obserable takiej jak ta.logger.log w metodzie isUserLoggedIn, generuje on błąd w pliku observer.js na tej metodzie: Observable.prototype._trySubscribe = funkcja (sink) { spróbuj { return this._subscribe (sink); } catch (err) { sink.syncErrorThrown = true; sink.syncErrorValue = err; sink.error (err); } }; – Fab

+0

Jest zarejestrowany w konstruktorze i działa poza obserwowalnym, ale nie wewnątrz – Fab

+0

Naprawdę tylko dostaję błędy wewnątrz .reduce, jeśli próbuję użyć wstrzykniętej usługi. – Fab

1

Metodamoże zwrócić wartość: Observable,lub Boolean, a Angular będzie wiedział, że powinien ją rozwinąć i obsłużyć wszystko asynchronicznie. Możesz zmienić swój kod, aby sprawdzić niezbędne dane, zanim zwrócisz albo zakończony/nieudany Observable lub rozwiązany/odrzucony Promise do routera kątowego i wywołanie this.naviationService.AccessDenied() w wyniku tej asynchronicznej funkcji.

+1

Jak to działa z przekierowanie z innego serwera/autoryzacji? Rozumiem Observables za pomocą interfejsu API danych, ale nie za dużo z przekierowaniem? czy możesz podać przykład kodu? Dzięki. – Fab

+0

Zasadniczo dzieje się tak, że twój 'AuthGuard' zostaje wywołany, zanim Angular ładuje trasę i komponent. W obecnej implementacji twoje "CanActivate" * natychmiast * zwraca wartość false i przechodzi do "AccessDenied". Wygląda na to, że coś skonfigurowano dla tej trasy lub zewnętrznego przekierowania, a następnie ponownie ładuje stronę, na której 'AuthGuard' zostaje ponownie uruchomiony i zwraca wartość true. W zależności od implementacji serwera auth, widzę, gdzie to może być trudne do wyplenienia. Możesz chcieć sprawdzić, czy okno czeka na przekierowanie, lub sprawdzić metodę 'rozwiązać' routera – joh04667

+0

... aby uzyskać dane dla komponentu, zanim faktycznie się załaduje. – joh04667

Powiązane problemy