2017-01-17 21 views
3

看起來好像我在這裏的圈子,也許是因爲使用這麼多的訂閱,並不得不將它們鏈接在一起。Angular2-jwt - AuthHttp,刷新標記,把它放在一起

我希望能夠刷新令牌,如果它使用刷新令牌過期。這就是我所擁有的,如果可能的話,我會非常感謝一個簡單的工作示例。總之,如何確保AudienceService首先檢查令牌是否有效,如果不是,它會嘗試使用刷新令牌對其進行刷新,然後使用相應令牌調用端點?

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

什麼不對的代碼?除非你想在你的每一個請求中包含刷新標記並自動刷新到後端,否則我認爲沒有其他辦法。 –

+0

你有沒有發現這個問題的解決方案?我有同樣的問題。 –

+0

@VinayPandya是的,我有。我會盡快發佈我的答案。 – blgrnboy

回答

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);'。不確定這是建議。基於[this](https://auth0.com/docs/tokens/refresh-token/current)文章,_a單頁應用程序(通常實現隱式授權)不應在任何情況下獲得刷新令牌。原因是這條信息的敏感性。您可以將其視爲用戶憑據,因爲刷新令牌可以讓用戶永久保持身份驗證狀態。因此你不能在瀏覽器中獲得這些信息,它必須安全地存儲。 – Voicu