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;
然后,将菜单代码分离到单独的<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
s 模板中使用*ngIf
显示菜单组件。
<app-menu *ngIf="authenticated"></app-menu>
替代方法是使用authenticated$
BehaviourSubject
,但我将把它留给其他答案。
【讨论】:
以上是关于Angular 8 在身份验证完成之前抑制 HTTP 调用的主要内容,如果未能解决你的问题,请参考以下文章
找不到在 Angular 中导入 Firebase 身份验证
WebApi.Owin 中的 SuppressDefaultHostAuthentication 也抑制 webapi 外部的身份验证