2017-08-10 447 views
1

我们正在使用React/Redux前端开发Spring应用程序。我们成功地将其与Keycloak认证服务整合在一起。但是,在访问令牌超时之后,我们遇到了不需要的行为。我们restMiddleware看起来像这样(简化):Keycloak |在异步函数中不能等待updateToken()

function restMiddleware() { 
    return (next) => async (action) => { 
     try{ 

      await keycloak.updateToken(5); 

      res = await fetch(restCall.url, { 
       ...restCall.options, ...{ 
        credentials: 'same-origin', 
        headers: { 
         Authorization: 'Bearer ' + keycloak.token 
        } 
       } 
      }); 

     }catch(e){} 
    } 

的问题是,该令牌过期和updateToken()被执行后,异步函数不停止,并调用取()立即收到新的访问令牌之前。这当然可以防止获取请求成功并导致代码401的响应。updateToken()返回一个Promise,所以我没有看到为什么await不起作用,这肯定会发生。

我确认函数updateToken().success(*function*)将在成功执行令牌刷新后执行,并将fetch()放入其中将解决问题,但由于我们的中间件构造,我无法做到这一点。我开发了这个解决方法:

function refreshToken(minValidity) { 

     return new Promise((resolve, reject) => { 

      keycloak.updateToken(minValidity).success(function() { 
       resolve() 
      }).error(function() { 
       reject() 
      }); 
     }); 
    } 

    function restMiddleware() { 
    return (next) => async (action) => { 
     try{ 
      await refreshToken(5); 

      res = await fetch(restCall.url, { 
       ...restCall.options, ...{ 
        credentials: 'same-origin', 
        headers: { 
         Authorization: 'Bearer ' + keycloak.token 
        } 
       } 
      }); 

     }catch(e){} 
    } 

它的工作原理,但它并不优雅。

问题是:为什么第一个解决方案不起作用?为什么我不能在updateToken()上等待并且必须使用updateToken()。success()呢?

我怀疑这可能是一个错误,并确认这是这个问题的主要目的。

回答

0

updateToken方法的文档声明它返回一个promise,但它实际上不是一个可用的,因此await关键字不认为它是一个有效的Promise。我就是这么说的。 :)

您的解决方案对我来说看起来很优雅,我也完成了同样的事情,以便在调用updateToken函数后在Promise链上正确继续。

Keycloak JavaScript的适配器文档:https://keycloak.gitbooks.io/documentation/securing_apps/topics/oidc/javascript-adapter.html

+1

我只是进去看了keycloak.js,在这种方法定义,我可以看到这一点。 updateToken()返回的内容根本不是Promise(来自ECMAScript规范)。这是一个自定义对象,其中只包含keycloak创建者指定的success()和error()函数...“承诺对象”-.- “updateToken方法返回一个承诺对象,该对象只有在令牌已成功刷新,例如,如果不是,则会向用户显示错误。“ 这是非常混乱的,我认为他们不应该使用这个描述。 – BJanusz

1

是的,正如所说,keycloak.js采用了自主开发的承诺,实施不兼容的ES6承诺。我在我的projetcs中倾向于做的是这里的一个小助手(TypeScript)。

export const keycloakPromise = <TSuccess>(keycloakPromise: KeycloakPromise<TSuccess, any>) => new Promise<TSuccess>((resolve, reject) => 
    keycloakPromise 
     .success((result: TSuccess) => resolve(result)) 
     .error((e: any) => reject(e)) 
); 

,并使用它像

keycloakPromise<KeycloakProfile>(keycloak.loadUserProfile()) 
    .then(userProfile => ...) 
    .catch(() => ...)