问题描述
因此,我对页面的标头部分进行了API调用,这是app.component.html的一部分。然后,我的路由模块中有几个具有canActivate的屏幕。只有路由到这些屏幕才能触发auth.guard,然后进行身份验证。但是由于此菜单代码位于app.component.html中。甚至在我没有令牌并且console.log中出现401错误之前,都会进行呼叫。有没有办法在身份验证结束之前阻止此呼叫,即我有刷新,ID和访问令牌?
LEFT OUTER JOIN cover_photo
ON cover_photo.idcover_photo = organization.idorganization
AND cover_photo.thumbnail = true
WHERE organization.idorganization_type = 1
HAVING distance < 20
app-routing module
const routes: Routes = [
{ path: 'abc',component:abcComponent,canActivate: [AuthGuard] },{path: 'xyz',component:xyzComponent,canActivate: [AuthGuard] }
];
app.component.ts
ngOnIt(){
this.httpService.getMenu().subscribe((response) => {
this.menuArray=response
});
}
所以我尝试了
export class TokenInterceptorService implements HttpInterceptor {
private isRefreshing = false;
private refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
constructor(private injector: Injector) {}
intercept(req: HttpRequest<any>,next: HttpHandler): Observable<HttpEvent<any>> {
if (req.url == environment.authTokenPostUrl) {
const tokenreq = req.clone({});
return next.handle(tokenreq);
} else {
const tokenreq = this.addToken(req);
return next.handle(tokenreq).pipe(
catchError((error) => {
const cookie = this.injector.get(CookieService);
if (error.status === 401) {
return this.handle401Error(tokenreq,next);
} else {
return throwError(error);
}
})
);
}
}
private addToken(request: HttpRequest<any>) {
const authservice = this.injector.get(AuthService);
const headers = { Authorization: `Bearer ${authservice.setIdToken()}` };
return request.clone({
setHeaders: headers,});
}
private handle401Error(request: HttpRequest<any>,next: HttpHandler) {
if (!this.isRefreshing) {
const authservice = this.injector.get(AuthService);
this.isRefreshing = true;
this.refreshTokenSubject.next(null);
return authservice.refreshToken().pipe(
switchMap((token: any) => {
this.isRefreshing = false;
this.refreshTokenSubject.next(token.id_token);
return next.handle(this.addToken(request));
})
);
} else {
return this.refreshTokenSubject.pipe(
filter((token) => token != null),take(1),switchMap((jwt) => {
return next.handle(this.addToken(request));
})
);
}
}
}
但是此逻辑不起作用,因为在触发此调用之后进行身份验证。
有没有办法解决这个问题?
解决方法
尽管RxJS解决方案可能更优雅(我建议您深入研究),但我会逆流而上,提供一个更“老派”的解决方案。它使用简单的属性,看不到$符号。对于经验不足的程序员,这可能是一个不错的选择,同时又保留了可维护性。
在您的AuthService中,创建一个名称为authenticated
的属性。验证后将其设置为true
。
class AuthService {
authenticated = false;
authenticate(params) {
this.http.post([authentication stuff]).subscribe(() => {
// do what you do now
this.authenticated = true;
}
}
然后,在单独的<app-menu>
组件中将菜单代码分开。
class MenuComponent {
ngOnInit() {
this.httpService.getMenu().subscribe((response) => {
this.menuArray=response
});
}
}
在主AppComponent
中,链接身份验证服务并通过getter代理authenticated
属性。
class AppComponent {
get authenticated() { return this.authService.authenticated; }
constructor(authService: AuthService) {}
}
然后,在AppComponent
的模板中,使用*ngIf
显示菜单组件。
<app-menu *ngIf="authenticated"></app-menu>
另一种方法是使用authenticated$
BehaviourSubject
,但我将其留给其他答案。