【问题标题】:Angular 8 suppress HTTP calls before authentication is completeAngular 8 在身份验证完成之前抑制 HTTP 调用
【发布时间】: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 将接口用于生命周期方法。

标签: angular typescript authentication jwt-auth angular-http-interceptors


【解决方案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,但我将把它留给其他答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多