所以我有这个非常标准的带有后端API的ReactJs / Redux项目。该API是安全的,并且由于该项目支持各种id提供程序(Azure AD,Google等,由后端处理并生成统一的auth cookie),因此我使用的是cookie身份验证。
此cookie的寿命有限,我正在通过提供自动更新auth cookie的方法来改善用户体验。
我的策略是这样-如果ajax请求或“获取用户信息”失败并显示401,并且已经选择了登录提供程序(我正在存储用户选择的登录提供程序),则该应用应创建一个所选登录端点(即https://myapi.com/login/azure)看不见的iframe,在大多数情况下,它将自动登录大多数用户。
我正在尝试将其与我的api模块集成。我的目标是尝试(例如)执行GET请求-如果该请求失败并显示401(加上用户已设置登录类型),则我想显示iframe,并在设置的时间段后重试该请求。如果仍然失败,我将重定向到登录页面。
理想情况下,我想从api模块调用分派,以便可以以受控方式显示iframe,但api模块不是组件,也不能连接到redux。它只是公开了各种方法,例如
export const getApps = (key) => {
return apiRequest(`/api/v0/organization/${key}/apps`);
};
或者,我可以尝试直接在api模块中操作DOM,但这似乎很脏。
你们有没有遇到过类似的情况,您是如何解决的?
编辑:
我采用了最短的路线,因为它在应用程序逻辑的其余部分之外(并且我可以将其包含在api服务中)-并遵循heretic-monkey的评论。 / p>
我创建了一种将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()});
});
}
然后,在显示iframe(如果响应为401)之后,我对fetch进行了包装,以重试
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;
});
到目前为止,它看起来工作良好,并且不会使应用程序的其余部分杂乱无章。
答案 0 :(得分:0)
我不确定您是否只需要直接DOM操作,但是您可以看一下React Portal(https://reactjs.org/docs/portals.html)。但是据我所知,您的问题足以将某种状态showLoginFrame
存储到您的redux存储中,并具有一个带有条件渲染的组件,例如
{showLoginFrame && <iframe .../>}
状态更改可以由某些具有setTimeout
的组件调度,该组件在令牌即将到期之前调用刷新。