角度8在身份验证完成之前禁止HTTP调用

问题描述

因此,我对页面的标头部分进行了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,但我将其留给其他答案。