簡體   English   中英

Angular 8 在身份驗證完成之前抑制 HTTP 調用

[英]Angular 8 suppress HTTP calls before authentication is complete

所以我有一個 API 調用我頁面的 header 部分,它是 app.component.html 的一部分。 然后我的路由模塊中有幾個屏幕有 canActivate。 只有路由到這些屏幕才能觸發 auth.guard 然后進行身份驗證。 但是由於這個菜單代碼在 app.component.html 里面。 甚至在我有令牌之前就已經進行了調用,並且我在 console.log 中出現了 401 錯誤。 有沒有辦法在身份驗證結束之前阻止此調用,即我有刷新、ID 和訪問令牌?

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));
                })
            );
        }
    }
}


所以我試過了

ngOnIt(){
    if(this.cookieService.get('refresh_token'))
        this.httpService.getMenu().subscribe((response) => {
            this.menuArray=response
        });
    }
}

但是這個邏輯不起作用,因為身份驗證是在觸發此調用之后發生的。

有辦法解決這個問題嗎?

雖然 RxJS 解決方案可能更優雅(我建議您深入研究),但我將 go 逆流而上,並提供更“老式的角度”解決方案。 它使用簡單的屬性,看不到 $ 符號。 對於經驗不足的程序員來說,這可能是一個不錯的選擇,同時保持了可維護性。

在您的 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中,鏈接 auth 服務並通過 getter 代理已authenticated的屬性。

class AppComponent {
  get authenticated() { return this.authService.authenticated; }
  constructor(authService: AuthService) {}
}

然后,在AppComponent的模板中使用*ngIf來顯示菜單組件。

<app-menu *ngIf="authenticated"></app-menu>

另一種方法是使用經過authenticated$ BehaviourSubject ,但我會把它留給其他答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM