0

所以我有这个带有后端 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;
    });

到目前为止,它看起来运行良好,并且不会弄乱应用程序的其余部分。

4

1 回答 1

0

我不确定您是否只需要直接的 DOM 操作,但您可以查看 React Portal ( https://reactjs.org/docs/portals.html )。但据我了解您的问题应该足以将某种状态showLoginFrame存储到您的 redux 商店并拥有一个具有条件渲染的组件,例如

{showLoginFrame && <iframe .../>}

状态更改可以由某个组件分派,该组件具有一个setTimeout在令牌到期之前调用刷新的组件。

于 2019-05-03T22:20:17.333 回答