源代码如下:
function federatedLogout() {
var mRemoteSystems,
aRemoteLogoutPromises = [];
if (fnStorageEventListener) {
// IE sends localStorage events also to the issuing window, -
// this is not needed hence we remove the listener in general at that point
window.removeEventListener('storage', fnStorageEventListener);
}
sap.ushell.utils.localStorageSetItem(sSessionTerminationKey, "pending");
suppressOData();
mRemoteSystems = getRemoteSystems();
Object.keys(mRemoteSystems).forEach(function (sAlias) {
try {
aRemoteLogoutPromises.push(
createAdapter("Container", mRemoteSystems[sAlias]).logout(false)
);
} catch (e) {
jQuery.sap.log.warning("Could not create adapter for " + sAlias,
e.toString(), "sap.ushell.Container");
}
oLocalStorage.removeItem(sRemoteSystemPrefix + sAlias);
});
// wait for all remote system logouts to be finished
// Note: We use done() and not always(), and we require all adapters to resolve
// their logout(false) in any case. If we use always() and any adapter's promise is
// rejected, the deferred object from when() is *immediately* rejected, too. Then
// the redirect happens before all remote logouts are finished.
// TODO force logoutLogonSystem after timeout?
jQuery.when.apply(jQuery, aRemoteLogoutPromises).done(logoutLogonSystem);
}
if (typeof oAdapter.addFurtherRemoteSystems === 'function') {
oAdapter.addFurtherRemoteSystems().always(federatedLogout);
} else {
federatedLogout();
}
return oDeferred.promise();
};
这段 SAP UI5 源代码是实现一个名为 federatedLogout 的函数,该函数用于执行联邦式登出(federated logout)操作。联邦式登出是指在多个远程系统中注销用户,通常在单点登录(SSO)场景下使用。下面我将逐步解释这段代码的逻辑。
初始化变量:
var mRemoteSystems,
aRemoteLogoutPromises = [];
在这里,声明了两个变量 mRemoteSystems 和 aRemoteLogoutPromises。mRemoteSystems 用于存储远程系统的信息,而 aRemoteLogoutPromises 是一个用于存储远程注销操作的 Promise 数组。
移除事件监听器:
if (fnStorageEventListener) {
window.removeEventListener('storage', fnStorageEventListener);
}
这段代码通过判断是否存在 fnStorageEventListener 函数来确定是否需要移除本地存储事件监听器。在这里,移除了与 fnStorageEventListener 相关联的 storage 事件监听器,该监听器可能是为了处理 IE 浏览器发送的本地存储事件。
设置本地存储项:
sap.ushell.utils.localStorageSetItem(sSessionTerminationKey, "pending");
设置了本地存储中的一个项,其键为 sSessionTerminationKey,值为字符串 “pending”。这个操作可能用于在本地标记会话终止的状态。
调用 suppressOData 函数:
suppressOData();
执行了一个名为 suppressOData 的函数。根据函数名,这可能是用于抑制 OData 请求的操作,以确保在注销期间不发送不必要的请求。
获取远程系统信息:
mRemoteSystems = getRemoteSystems();
调用了一个名为 getRemoteSystems 的函数,用于获取远程系统的信息,并将其存储在 mRemoteSystems 中。
迭代远程系统并执行注销操作:
Object.keys(mRemoteSystems).forEach(function (sAlias) {
try {
aRemoteLogoutPromises.push(
createAdapter(`Container`, mRemoteSystems[sAlias]).logout(false)
);
} catch (e) {
jQuery.sap.log.warning(`Could not create adapter for ${sAlias}`,
e.toString(), `sap.ushell.Container`);
}
oLocalStorage.removeItem(sRemoteSystemPrefix + sAlias);
});
通过迭代 mRemoteSystems 中的远程系统,使用 createAdapter 函数创建适配器,并调用其 logout 方法执行注销操作。成功创建的注销 Promise 被添加到 aRemoteLogoutPromises 数组中。如果创建适配器或注销操作失败,会记录相应的警告信息,并从本地存储中移除相关的项。
等待所有远程系统注销完成:
jQuery.when.apply(jQuery, aRemoteLogoutPromises).done(logoutLogonSystem);
使用 jQuery.when 函数等待所有的远程系统注销 Promise 完成。一旦所有的 Promise 都完成,将调用 logoutLogonSystem 函数。
处理进一步的远程系统:
if (typeof oAdapter.addFurtherRemoteSystems === 'function') {
oAdapter.addFurtherRemoteSystems().always(federatedLogout);
} else {
federatedLogout();
}
检查适配器是否提供了 addFurtherRemoteSystems 方法,如果是,则调用该方法获取进一步的远程系统信息,并始终执行 federatedLogout 函数。如果适配器不提供此方法,则直接调用 federatedLogout 函数。
返回 Promise:
return oDeferred.promise();
最后,返回一个 Promise 对象,该对象可能用于链式调用或其他异步处理。
总体而言,这段代码实现了一种联邦式登出的逻辑,通过迭代远程系统,调用相应的适配器执行注销操作,然后等待所有远程系统注销完成后再执行进一步的处理。这样的设计适用于多系统环境下的用户注销场景,确保用户在所有系统中都被正确注销。