Angular 8 在身份验证完成之前抑制 HTTP 调用

Posted

技术标签:

【中文标题】Angular 8 在身份验证完成之前抑制 HTTP 调用【英文标题】:Angular 8 suppress HTTP calls before authentication is complete 【发布时间】:2021-01-24 07:18:57 【问题描述】:

所以我有一个 API 调用我的页面的标题部分,它是 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; intercept 返回一个 observable,所以你可以例如公开一个可观察的令牌,从而阻止拦截器中的请求,直到它可用。但请注意它是 ngOnInit,这就是为什么 Angular recommends 将接口用于生命周期方法。 【参考方案1】:

虽然 RxJS 解决方案可能更优雅(我建议您深入研究),但我将逆流而上,提供更“老派角度”的解决方案。它使用普通属性,看不到 $ 符号。对于经验不足的程序员来说,这可能是一个不错的选择,同时保持可维护性。

在您的 AuthService 中,创建一个名为 authenticated 的属性。验证后将其设置为 true

class AuthService 
    authenticated = false;

    authenticate(params) 
      this.http.post([authentication stuff]).subscribe(() => 
        // do what you do now
        this.authenticated = true;
   

然后,将菜单代码分离到单独的&lt;app-menu&gt; 组件中。

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) 

然后,在AppComponents 模板中使用*ngIf 显示菜单组件。

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

替代方法是使用authenticated$BehaviourSubject,但我将把它留给其他答案。

【讨论】:

以上是关于Angular 8 在身份验证完成之前抑制 HTTP 调用的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2+等待方法/可观察完成

找不到在 Angular 中导入 Firebase 身份验证

WebApi.Owin 中的 SuppressDefaultHostAuthentication 也抑制 webapi 外部的身份验证

Laravel Tymon\JWT Auth:在身份验证之前检查未完成的有效令牌?

Angular 6在令牌更新后重制请求之前更改JWT令牌

向 Autodesk 进行身份验证