2017-01-17 3 views
3

Es scheint so, als würde ich hier im Kreis gehen, und vielleicht ist es wegen der Verwendung von so vielen Abonnements und müssen sie zusammen zu ketten.Angular2-jwt - AuthHttp, Refresh Tokens, setzen alles zusammen

Ich möchte ein Token aktualisieren können, wenn es mit dem Aktualisierungstoken abgelaufen ist. Hier ist, was ich habe, und ich würde wirklich ein einfaches Arbeitsbeispiel schätzen, wenn möglich.

Zusammenfassend, wie kann ich sicherstellen, dass der AudienceService zunächst überprüft, ob das Token gültig ist, wenn nicht, versucht es, es mithilfe des Aktualisierungstokens zu aktualisieren, und dann einen Aufruf an den Endpunkt mit dem entsprechenden Token?

app.module.ts:

import { BrowserModule } from '@angular/platform-browser'; 
import { NgModule } from '@angular/core'; 
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 
import { HttpModule } from '@angular/http'; 
import { RouterModule } from '@angular/router'; 
import { Http, RequestOptions } from '@angular/http'; 
import { ConfirmDialogModule, ListboxModule, PickListModule } from 'primeng/primeng'; 

import { AppComponent } from './app.component'; 
import { HeaderComponent } from './components/header/header.component'; 
import { HomeComponent } from './components/home/home.component'; 
import { ListAudiencesComponent } from './components/audiences/list-audiences/list-audiences.component'; 

import { AudienceService } from './services/audience.service'; 
import { LoggingService } from './services/logging.service'; 
import { RoleService } from './services/role.service'; 
import { AuthService } from './services/auth.service'; 
import { UserService } from './services/user.service'; 
import { AuthGuard } from './services/auth-guard.service' 
import { AuthHttp, AuthConfig, provideAuth } from 'angular2-jwt'; 
import { ListRolesComponent } from './components/roles/list-roles/list-roles.component'; 
import { EditRoleAudiencesComponent } from './components/roles/edit-role-audiences/edit-role-audiences.component'; 
import { ModifyRoleComponent } from './components/roles/modify-role/modify-role.component'; 
import { LoginComponent } from './components/login/login.component'; 
import { UnauthorizedComponent } from './components/unauthorized/unauthorized.component'; 

export function authHttpServiceFactory(http: Http, options: RequestOptions) { 
    return new AuthHttp(new AuthConfig({ 
    tokenName: 'token', 
      tokenGetter: (() => sessionStorage.getItem('id_token')), 
      globalHeaders: [{'Content-Type':'application/json'}], 
    }), http, options); 
} 

@NgModule({ 
    declarations: [ 
    AppComponent, 
    HeaderComponent, 
    HomeComponent, 
    ListAudiencesComponent, 
    ListRolesComponent, 
    EditRoleAudiencesComponent, 
    ModifyRoleComponent, 
    LoginComponent, 
    UnauthorizedComponent 
    ], 
    imports: [ 
    BrowserModule, 
    ConfirmDialogModule, 
    FormsModule, 
    HttpModule, 
    ListboxModule, 
    PickListModule, 
    ReactiveFormsModule, 
    RouterModule.forRoot([ 
      { path: '', redirectTo: 'home', pathMatch: 'full' }, 
      { path: 'home', component: HomeComponent }, 
      { path: 'unauthorized', component: UnauthorizedComponent }, 
      { path: 'audiences', component: ListAudiencesComponent, canActivate: [AuthGuard] }, 
      { path: 'roles', component: ListRolesComponent, canActivate: [AuthGuard] }, 
      { path: 'roles/modify/:name', component: ModifyRoleComponent, canActivate: [AuthGuard] }, 
      { path: '**', redirectTo: 'home' } 
     ]), 
    ], 
    providers: [ 
    { 
     provide: AuthHttp, 
     useFactory: authHttpServiceFactory, 
     deps: [Http, RequestOptions] 
    }, 
    AudienceService, AuthGuard, AuthService, LoggingService, RoleService, UserService 
    ], 
    bootstrap: [AppComponent] 
}) 
export class AppModule { } 

auth.service.ts:

import { Injectable } from '@angular/core'; 
import { Http, Headers, RequestOptions, URLSearchParams } from '@angular/http'; 
import { environment } from '../../environments/environment'; 
import { tokenNotExpired } from 'angular2-jwt'; 

@Injectable() 
export class AuthService { 

    tokenEndpoint = environment.token_endpoint; 
    constructor(private http: Http) { } 

    login(username: string, password: string) { 
    let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' }); 
    let options = new RequestOptions({ headers: headers }); 
    let body = new URLSearchParams(); 
    body.set('username', username); 
    body.set('password', password); 
    body.set('client_id', '099153c2625149bc8ecb3e85e03f0022'); 
    body.set('grant_type', 'password'); 

    console.log("Got here"); 

    return this.http.post(this.tokenEndpoint, body, options) 
    .map(res => res.json()) 
    .subscribe(
     data => { 
      localStorage.setItem('id_token', data.access_token); 
      localStorage.setItem('refresh_token', data.refresh_token); 
     }, 
     error => console.log(error) 
    ); 
    } 

    loggedIn() { 
    if (tokenNotExpired()) { 
     return true; 
    } else { 
     this.refreshToken() 
     .subscribe(
      data => { 
      if (data.error) { 
       this.logout(); 
      } else { 
       localStorage.setItem('id_token', data.access_token); 
       localStorage.setItem('refresh_token', data.refresh_token); 
       console.log("Token was refreshed."); 
      } 
      }, 
      error => this.logout(), 
     () => { 
      return tokenNotExpired(); 
      } 
     ); 
    } 
    } 

    refreshToken() { 
    let refToken = localStorage.getItem('refresh_token'); 
    if (refToken) { 
     let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' }); 
     let options = new RequestOptions({ headers: headers }); 
     let body = new URLSearchParams(); 
     body.set('client_id', '099153c2625149bc8ecb3e85e03f0022'); 
     body.set('grant_type', 'refresh_token'); 
     body.set('refresh_token', refToken); 

     return this.http.post(this.tokenEndpoint, body, options) 
     .map(res => res.json()); 
    } else { 
     this.logout(); 
    } 
    } 

    tokenRequiresRefresh(): boolean { 
    if (!this.loggedIn()) { 
     console.log("Token refresh is required"); 
    } 

    return !this.loggedIn(); 
    } 

    logout() { 
    localStorage.removeItem('id_token'); 
    localStorage.removeItem('refresh_token'); 
    } 
} 

audience.service.ts:

import 'rxjs/Rx'; 
import { Observable } from 'rxjs/Observable'; 
import { environment } from '../../environments/environment'; 
import { AuthHttp } from 'angular2-jwt'; 
import { AuthService } from './auth.service'; 

import { AddDeleteAudienceModel } from './AddAudienceModel'; 

@Injectable() 
export class AudienceService { 

    baseApiUrl = environment.api_endpoint; 

    constructor(private http: Http, private authHttp: AuthHttp, private authService: AuthService) { } 

    getAllAudiences() 
    { 
    if (this.authService.tokenRequiresRefresh()) { 
     this.authService.refreshToken(); 
    } 

    if (this.authService.loggedIn()) { 
     return this.authHttp.get(this.baseApiUrl + 'audience/all').map(res => res.json()); 
    } 
    } 
} 
+0

was mit diesem Code falsch? Es sei denn, Sie möchten das Refresh-Token in jeden Ihrer Requests aufnehmen und automatisch im Backend aktualisieren. Ich glaube nicht, dass es einen anderen Weg gibt. –

+0

Haben Sie eine Lösung für dieses Problem gefunden? Ich habe das gleiche Problem. –

+0

@VinayPandya ja, ich habe. Ich werde meine Antwort in Kürze posten. – blgrnboy

Antwort

11

auth.service.ts

import { Injectable } from '@angular/core'; 
import { Router } from '@angular/router'; 
import { Http, Headers, RequestOptions, URLSearchParams } from '@angular/http'; 
import { environment } from '../../environments/environment'; 
import { tokenNotExpired, JwtHelper } from 'angular2-jwt'; 
import { Subject, Observable } from 'rxjs'; 

@Injectable() 
export class AuthService { 

    tokenEndpoint = environment.token_endpoint; 
    requireLoginSubject: Subject<boolean>; 
    tokenIsBeingRefreshed: Subject<boolean>; 
    lastUrl: string; 
    jwtHelper: JwtHelper = new JwtHelper(); 

    constructor(private http: Http, private router: Router) { 
    this.requireLoginSubject = new Subject<boolean>(); 
    this.tokenIsBeingRefreshed = new Subject<boolean>(); 
    this.tokenIsBeingRefreshed.next(false); 
    this.lastUrl = "/home"; 
    } 

    isUserAuthenticated() { 

    if(this.loggedIn()) { 
     this.requireLoginSubject.next(false); 
     return true; 
    } else { 
     return false; 
    } 
    } 

    login(username: string, password: string) { 
    let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' }); 
    let options = new RequestOptions({ headers: headers }); 
    let body = new URLSearchParams(); 
    body.set('username', username); 
    body.set('password', password); 
    body.set('client_id', '099153c2625149bc8ecb3e85e03f0022'); 
    body.set('grant_type', 'password'); 

    return this.http.post(this.tokenEndpoint, body, options).map(res => res.json()); 
    } 

    loggedIn() { 
    return tokenNotExpired(); 
    } 

    addTokens(accessToken: string, refreshToken: string) { 
    localStorage.setItem('id_token', accessToken); 
    localStorage.setItem('refresh_token', refreshToken); 
    } 

    getRefreshTokenExpirationDate() { 
    var token = localStorage.getItem('id_token'); 
    if (token) { 
     let tokenExpDate = this.jwtHelper.getTokenExpirationDate(token); 
     let sessionExpDate = new Date(tokenExpDate.getTime() + 4*60000); 
     if (new Date() > sessionExpDate) { 
     this.logout(); 
     } 
     return sessionExpDate; 
    } 

    return null; 
    } 

    hasRefreshToken() { 
    let refToken = localStorage.getItem('refresh_token'); 

    if (refToken == null) { 
     this.logout(); 
    } 

    return refToken != null; 
    } 

    refreshTokenSuccessHandler(data) { 
    if (data.error) { 
     console.log("Removing tokens."); 
     this.logout(); 
     this.requireLoginSubject.next(true); 
     this.tokenIsBeingRefreshed.next(false); 
     this.router.navigateByUrl('/unauthorized'); 
     return false; 
    } else { 
     this.addTokens(data.access_token, data.refresh_token); 
     this.requireLoginSubject.next(false); 
     this.tokenIsBeingRefreshed.next(false); 
     console.log("Refreshed user token"); 
    } 
    } 

    refreshTokenErrorHandler(error) { 
    this.requireLoginSubject.next(true); 
    this.logout(); 
    this.tokenIsBeingRefreshed.next(false); 
    this.router.navigate(['/sessiontimeout']); 
    console.log(error); 
    } 

    refreshToken() { 
    let refToken = localStorage.getItem('refresh_token'); 
    //let refTokenId = this.jwtHelper.decodeToken(refToken).refreshTokenId; 
    let headers = new Headers({ 'Content-Type': 'application/x-www-form-urlencoded' }); 
    let options = new RequestOptions({ headers: headers }); 
    let body = new URLSearchParams(); 
    body.set('client_id', '099153c2625149bc8ecb3e85e03f0022'); 
    body.set('grant_type', 'refresh_token'); 
    body.set('refresh_token', refToken); 

    return this.http.post(this.tokenEndpoint, body, options) 
     .map(res => res.json()); 
    } 

    tokenRequiresRefresh(): boolean { 
    if (!this.loggedIn()) { 
     console.log("Token refresh is required"); 
    } 

    return !this.loggedIn(); 
    } 

    logout() { 
    localStorage.removeItem('id_token'); 
    localStorage.removeItem('refresh_token'); 
    this.requireLoginSubject.next(true); 
    } 
} 

Auth-http.service.ts

import { Injectable } from '@angular/core'; 
import { Router } from '@angular/router'; 
import 'rxjs/Rx'; 
import { Observable } from 'rxjs/Observable'; 
import { environment } from '../../environments/environment'; 
import { AuthHttp } from 'angular2-jwt'; 
import { AuthService } from './auth.service'; 

@Injectable() 
export class AuthHttpService { 

    constructor(private authHttp: AuthHttp, private authService: AuthService, private router: Router) { } 

    get(endpoint: string) { 
    if (this.authService.tokenRequiresRefresh()) { 
     this.authService.tokenIsBeingRefreshed.next(true); 
     return this.authService.refreshToken().switchMap(
     (data) => { 
      this.authService.refreshTokenSuccessHandler(data); 
      if (this.authService.loggedIn()) { 
      this.authService.tokenIsBeingRefreshed.next(false); 
      return this.getInternal(endpoint); 
      } else { 
      this.authService.tokenIsBeingRefreshed.next(false); 
      this.router.navigate(['/sessiontimeout']); 
      return Observable.throw(data); 
      } 
     } 
    ).catch((e) => { 
     this.authService.refreshTokenErrorHandler(e); 
     return Observable.throw(e); 
     }); 
    } 
    else { 
     return this.getInternal(endpoint); 
    } 
    } 

    post(endpoint: string, body: string) : Observable<any> { 
    if (this.authService.tokenRequiresRefresh()) { 
     this.authService.tokenIsBeingRefreshed.next(true); 
     return this.authService.refreshToken().switchMap(
     (data) => { 
      this.authService.refreshTokenSuccessHandler(data); 
      if (this.authService.loggedIn()) { 
      this.authService.tokenIsBeingRefreshed.next(false); 
      return this.postInternal(endpoint, body); 
      } else { 
      this.authService.tokenIsBeingRefreshed.next(false); 
      this.router.navigate(['/sessiontimeout']); 
      return Observable.throw(data); 
      } 
     } 
    ).catch((e) => { 
     this.authService.refreshTokenErrorHandler(e); 
     return Observable.throw(e); 
     }); 
    } 
    else { 
     return this.postInternal(endpoint, body); 
    } 
    } 

    private getInternal(endpoint: string) { 
    return this.authHttp.get(endpoint); 
    } 

    private postInternal(endpoint: string, body: string) { 
    return this.authHttp.post(endpoint, body); 
    } 

} 

audience.service.ts

import { Injectable } from '@angular/core'; 
import 'rxjs/Rx'; 
import { Observable } from 'rxjs/Observable'; 
import { environment } from '../../environments/environment'; 
import { AuthHttpService } from './auth-http.service'; 

import { AddDeleteAudienceModel } from './AddAudienceModel'; 

@Injectable() 
export class AudienceService { 

    baseApiUrl = environment.api_endpoint; 

    constructor(private authHttpService: AuthHttpService) { } 

    getAllAudiences() 
    { 
    return this.authHttpService.get(this.baseApiUrl + 'audience/all').map(res => res.json()); 
    } 

    addAudience(model: AddDeleteAudienceModel) { 
    return this.authHttpService.post(this.baseApiUrl + 'audience', JSON.stringify(model)).map(res => res.json()); 
    } 

    deleteAudience(model: AddDeleteAudienceModel) { 
    return this.authHttpService.post(this.baseApiUrl + 'audience/delete', JSON.stringify(model)).map(res => res.json()); 
    } 

} 
+0

'localStorage.setItem ('refresh_token', refreshToken);'. Nicht sicher, dass dies empfohlen wird. Basierend auf dem Artikel [this] (https://auth0.com/docs/tokens/refresh-token/current) sollte _ eine Einzelseitenanwendung (die normalerweise Implicit Grant implementiert) unter keinen Umständen ein Aktualisierungstoken erhalten. Der Grund dafür ist die Empfindlichkeit dieser Information. Sie können es sich als Benutzeranmeldeinformationen vorstellen, da ein Aktualisierungstoken es einem Benutzer ermöglicht, im Wesentlichen für immer authentifiziert zu bleiben. Daher können Sie diese Informationen nicht in einem Browser speichern, sie müssen sicher gespeichert werden. – Voicu

Verwandte Themen