正如我在问题中提到的,获取是否登录的相对状态是没有问题的。问题在于 iframe,因为只有 iframe 知道发生了什么(因为它是重定向的 url!)。让我的主应用程序也响应。我做了一些调整和“黑客”。
这是我如何让它工作的。它会检测我是否在其他地方登录并自动登录。如果我在另一个站点注销,它也会在我的应用程序中注销。
* 检测我是否在其他地方登录 *
我创建了一个方法'checkLoginState',它负责检查我的会话中是否有令牌或检查服务器是否我已经登录。
间隔只是定期检查如果 iframe 获得了令牌。
checkLoginState() {
const claims = this.oauthService.getIdentityClaims();
if (!claims) {
if (this.ssoInterval) {
// if we are waiting on response, return;
return;
}
// try to get a token if already logged in somewhere else
this.oauthService
.loadDiscoveryDocument()
.then(() => this.oauthService.tryLogin())
.then(() => {
if (!this.oauthService.hasValidAccessToken()) {
this.setupSSOInterval();
this.oauthService.silentRefresh().catch(err => {
// this will throws a time_out error as we don't have a
valid token to refresh
// console.error('refresh error', err);
this.clearSSOInterval();
});
}
})
.catch(e => {
// console.log(e);
// if not logged in anywhere, it will throw a token error.
this.clearSSOInterval();
});
return;
}
if (this.oauthService.getIdTokenExpiration() < new Date().getTime()) {
this.userService.removeToken();
return this.logout();
}
this.isLoggedIn = true;
this.userService.authenticateWithNID(claims['email']);
}
private setupSSOInterval() {
this.ssoInterval = setInterval(() => {
if (this.isLoggedIn) {
clearInterval(this.ssoInterval);
} else {
this.checkLoginState();
}
}, 1000);
}
private clearSSOInterval() {
if (this.ssoInterval) {
clearInterval(this.ssoInterval);
}
}
并在 ngOnInit() 中调用此方法;
* 检测我是否在其他地方注销 *
要检测我是否已注销,首先将其设置sessionChecksEnabled为 true(如 @Jeroen 所说)。然后监听会话存储的变化。(因为 iframe 会更新会话存储)
ngOnInit() {
window.addEventListener(
'storage',
this.storageEventListener.bind(this)
);
// this is for handle the normal redirect when we login from this app
this.oauthService.events.subscribe(({ type }: OAuthEvent) => {
switch (type) {
case 'token_received': {
this.checkLoginState();
}
}
});
this.checkLoginState();
}
private storageEventListener(event: StorageEvent) {
// if there is a session change and claims is missing, means I am no longer logged in
if (event.storageArea === sessionStorage) {
if (!sessionStorage.getItem('id_token_claims_obj')) {
this.isLoggedIn = false;
}
}
}
请记住删除this.oauthService.loadDiscoveryDocumentAndTryLogin();构造函数方法中的 。如果您在其他站点注销,它将引发一些错误。(如果需要,您可以捕获错误,但内部调用了相同的方法checkloginState())。
我刚刚意识到我也可以使用会话存储侦听器进行登录检查(替换间隔)。但我会暂时离开它。