我创建了一个身份验证服务,用于检查本地存储中访问令牌的存在。为此,我创建了一个称为hasValidAccessToken
的可观察对象。该函数发出boolean
值。
我在app-component
中观察到该订阅。问题是我无法取消订阅app-component
中的订阅,因为它从未被销毁。
authentication.service.ts
public isAuthenticatedSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(this.hasValidAccessToken());
public isAuthenticated$: Observable<boolean>;
isTokenExpired(): boolean {
const expiresAt = localStorage.getItem("expires_at");
const now = new Date();
if (
expiresAt &&
parseInt(expiresAt, 10) < Math.floor(now.getTime() / 1000)
) {
return false;
}
return true;
}
hasValidAccessToken(): boolean {
if (this.hasAccessToken()) {
return this.isTokenExpired();
}
return false;
}
hasAccessToken(): boolean {
return !!localStorage.getItem("access_token");
}
decodeToken(token: string) {
if (token) {
return jwt_decode(token);
}
}
app.component.ts
this.isAuthenticatedSubscription = this.oauthService.isAuthenticated$.subscribe(
data => {
if (data) {
this.router.navigate(["home"]);
} else {
this.router.navigate(["login"], {
state: { data: "session has been expired" }
});
}
}
);
答案 0 :(得分:3)
您可以使用take在设置一定数量的发射量之后使您的Observable完整。
this.isAuthenticatedSubscription = this.oauthService.isAuthenticated$
.pipe(
take(1)
)
.subscribe(
data => {
if (data) {
this.router.navigate(["home"]);
} else {
this.router.navigate(["login"], {
state: { data: "session has been expired" }
});
}
}
);
编辑:尽管这可以解决您的问题,但@Dino是正确的,您不应该取消订阅该可观察的内容,因为您的应用程序的登录状态取决于此。您应该将此逻辑移至AuthGuard。
答案 1 :(得分:3)
您永远不应取消订阅该可观察的项目。您基本上是在重新创建Authentication Guard。想象一下,如果您确实取消订阅它,并且在应用程序中的某一时刻,您丢失了身份验证令牌(注销,否则它将过期...)。由于您已取消订阅该应用程序,因此该代码将永远不会触发:
else {
this.router.navigate(["login"], {
state: { data: "session has been expired" }
});
}
我的建议是通过创建前面提到的Authentication Guard来替换逻辑。这样,您将可以使用canActivate保护路线,这也是最佳做法。