Angular2-jwt - AuthHttp,刷新令牌,把它们放在一起
Posted
技术标签:
【中文标题】Angular2-jwt - AuthHttp,刷新令牌,把它们放在一起【英文标题】:Angular2-jwt - AuthHttp, refresh tokens, putting it all together 【发布时间】:2017-06-02 00:24:20 【问题描述】:我好像在这里转了一圈,也许是因为使用了这么多订阅并且不得不将它们链接在一起。
如果令牌过期,我希望能够使用刷新令牌刷新令牌。这就是我所拥有的,如果可能的话,我非常感谢一个简单的工作示例。
总之,我如何确保 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());
【问题讨论】:
这段代码有什么问题?除非您想在每个请求中包含刷新令牌并在后端自动刷新,否则我认为没有其他方法。 你找到解决这个问题的方法了吗?我有同样的问题。 @VinayPandya 是的,我有。我会尽快发布我的答案。 【参考方案1】: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());
【讨论】:
localStorage.setItem('refresh_token', refreshToken);
。不确定这是推荐的。根据this 文章,单页应用程序(通常实现隐式授予)在任何情况下都不应该获得刷新令牌。原因是这条信息的敏感性。您可以将其视为用户凭据,因为刷新令牌允许用户基本上永远保持身份验证。因此,您无法在浏览器中获取此信息,它必须安全存储。以上是关于Angular2-jwt - AuthHttp,刷新令牌,把它们放在一起的主要内容,如果未能解决你的问题,请参考以下文章
Angular 6 中的 AuthHttp(从 Angular2 迁移到 Angular6)