所以我有这个带有后端 API 的非常标准的 ReactJs/Redux 项目。API 是安全的,我正在使用 cookie 身份验证,因为该项目支持各种 id 提供程序(Azure AD、Google 等,由后端处理并生成统一的身份验证 cookie)。
此 cookie 的使用寿命有限,我正在努力通过提供身份验证 cookie 的自动更新来改善用户体验。
我的策略是这样的 - 如果 ajax 请求或我的“获取用户信息”失败并出现 401,并且已经选择了登录提供程序(我正在存储登录提供程序的用户选择),应用程序应该创建一个不可见的 iframe选择的登录端点(即https://myapi.com/login/azure),在大多数情况下将自动登录大多数用户。
我正在尝试将其与我的 api 模块集成。我的目标是尝试(例如)一个 GET 请求 - 如果 401 失败(加上用户设置了登录类型),我想显示 iframe 并在一段时间后重试请求。如果仍然失败,我将重定向到登录页面。
理想情况下,我想从 api 模块调用调度,以便 iframe 可以以受控方式显示,但 api 模块不是组件,也没有连接到 redux。它只是公开了各种方法,例如
export const getApps = (key) => {
return apiRequest(`/api/v0/organization/${key}/apps`);
};
或者,我可以尝试直接在 api 模块中操作 DOM,但这似乎有点脏。
你们中有人处理过类似的情况吗?你们是如何解决的?
编辑:
我用这条最短的路线,因为它有点超出应用程序逻辑的其余部分(我可以通过这种方式将它包含在 api 服务中) - 并遵循heetic-monkey的评论。
我创建了一种方法来将 iframe 添加到登录端点并在设定的时间段后将其删除(我使用两秒)。
const createLoginIframe = (waitTime) =>{
return new Promise(function(resolve) {
var iframe = document.createElement('iframe');
iframe.setAttribute("src",login.endpoint);
iframe.setAttribute("style","position:absolute;left:-5000px;");
var auth =document.getElementById("auth");
auth.appendChild(iframe);
delay(waitTime).then(()=>{auth.removeChild(iframe); resolve()});
});
}
然后我做了一个 fetch 包装器,在显示 iframe 后重试(如果响应是 401)
const fetchGetWithRetry = (url, secondAttempt) => fetch(url, {
method: "GET",
mode:'cors',
credentials: "include",
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
}).then(response => {
if (response.status === 401){
if (!secondAttempt){
return createLoginIframe(iframeWaitTime).then(function(){
return fetchGetWithRetry(url, true)
})
}
else{
return {error:'NOAUTH'}
}
}
return response;
});
到目前为止,它看起来运行良好,并且不会弄乱应用程序的其余部分。