[英]How to call an async method in canActivate with angular?
我正在嘗試為Angular 4.2.4中的管理路由實現canActivate保護。
基於此堆棧問題: canActivate Question ,我認為我做的一切正確。 但是,a,我似乎無法使事情正常進行。
這是模塊防護:
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private _store: Store<AppState>,
private router: Router,
private czauth: CzauthService) { }
canActivate(route: ActivatedRouteSnapshot):Observable<boolean>{
return this.czauth.verifyAdminUser().first();
}
};
這是我的czauth服務:
getToken():Observable<firebase.User>{
return this.af.idToken;
}
verifyUserRole(token){
this.token = token;
console.log(token);// Log out "PromiseObservable {_isScalar: false, promise: D, scheduler: undefined}"
let headers = new Headers({ 'Authorization': 'Bearer ' + token});
let options = new RequestOptions({ headers: headers });
return this.http.get(environment.api+'/verifyadminuser', options).map((response)=>{return response.json()});
}
verifyAdminUser():Observable<boolean>{
return this.getToken()
.map((user)=>{return Observable.fromPromise(user.getIdToken())})
.map((token)=>{return this.verifyUserRole(token)})
.do((response)=>{console.log(response)})// Always returns "Observable {_isScalar: false, source: Observable, operator: MapOperator}"
.switchMap((response:any)=>{ return response.status === 200 ? Observable.of(true) : Observable.of(false)});
}
我永遠無法從我的http異步調用獲得響應。 在控制台中,我總能感覺到寒冷。 好像路由器從不訂閱我的觀察者嗎? 我想根據我的http響應返回一個布爾值。 我該如何實現?
編輯:
我正在從警衛人員調用verifyAdminUser
方法。 該服務是根模塊上的一個模塊。 防護措施可保護對延遲加載的模塊的訪問。
下面,我列出了在路由中使用保護的位置。
路由模塊:
const routes: Routes = [
{path: '', loadChildren : './landing/landing.module#LandingModule'},
{path: 'dashboard', loadChildren : './dashboard/dashboard.module#DashboardModule', canActivate: [ AuthGuard ]}
];
@NgModule({
imports: [RouterModule.forRoot(routes, {preloadingStrategy: PreloadAllModules})],
exports: [RouterModule]
})
export class AppRoutingModule { }
問題是當用戶嘗試導航到儀表板模塊時,canActivate始終返回false,因為在switchMap運算符中的響應未定義。
編輯2:
我在代碼中重構並簡化了以下兩種方法,現在一切正常。 現在,我試圖了解原因。 以下是調整后的方法:
verifyUserRole(){
let headers = new Headers({ 'Authorization': 'Bearer ' + this.token});
let options = new RequestOptions({ headers: headers });
return this.http.get(environment.api+'/verifyadminuser', options).map((response)=>{return response});
}
verifyAdminUser():Observable<boolean>{
return this.getToken()
.map((user)=>{
user.getIdToken().then((token)=>this.token = token);
return user;
})
.map(()=>{return this.verifyUserRole})
.switchMap((response:any)=>{ return response ? Observable.of(true) : Observable.of(false)});
}
解:
感謝下面的@BeetleJuice出色答案,我得以創建一個派生解決方案。 這是我重構的兩種方法:
verifyUserRole(token){
this.token = token;
let headers = new Headers({ 'Authorization': 'Bearer ' + token});
let options = new RequestOptions({ headers: headers });
return this.http.get(environment.api+'/verifyadminuser', options).map((response)=>{return response});
}
verifyAdminUser():Observable<boolean>{
return this.getToken()
.switchMap((user)=>{return Observable.fromPromise(user.getIdToken())})
.switchMap((token)=>{return this.verifyUserRole(token)})
.map((response:any)=>{ return response.status === 200 ? true : false});
}
注意此行,取自verifyUserRole
console.log(token);// Log out "PromiseObservable...
因此token
是可以觀察到的,但是您在下一行將其視為字符串,因此服務器可能會拒絕該請求
let headers = new Headers({ 'Authorization': 'Bearer ' + token})
您正在濫用verifyAdminUser()
的.map
運算符。 map
僅應與同步功能一起使用。 例如:
// this works if user.id is a property available immediately
return this.getToken().map(user => user.id)
map
不應與異步函數一起使用。 例如:
// this fails since the return value is an Observable that will resolve later
return this.getToken().map(user => Observable.fromPromise(...))
map
立即返回。 結果,沿着鏈條傳遞的不是您期望的令牌本身,而是將來會生成令牌的Observable。 這就是為什么console.log(token)
給您“ PromiseObservable”的原因。 您需要的是一個運算符,它將等待其中的可觀察值產生,然后將發出的值傳遞給下一個運算符。 使用switchMap
//this will work; switchMap waits for Obervable.fromPromise
// to emit before continuing
return this.getToken().switchMap(user => Observable.fromPromise(...))
因此,基本上,代替map
用switchMap
在線3和4 verifyAdminUser
。 您還可以通過執行相反的verifyAdminUser
來簡化verifyAdminUser
的最后一行:
.switchMap((response:any)=>{ return response.status === 200 ? Observable.of(true) : Observable.of(false)})
與
// no need for switchMap because response.status is available immediately
.map(res => res.status===200? true: false)
另外,您使用的canActivate
錯誤。 這是為了防止激活組件。 為防止加載延遲加載的模塊,請使用canLoad保護。 所以我想要么更換canActivate
與canLoad
(如果我要保護整個模塊),或移動canActivate
后衛到具有特定的路線component:
內財產DashboardRoutingModule
(我猜的名字)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.