如何确保令牌在预检调用之间不会过期?

How can I ensure a token doesn't expire between preflight calls?

我遇到了 Keycloak 的间歇性问题。如果用户触发预检 API 调用并且 Keycloak 的令牌在该调用和实际 API 调用之间过期,预检调用将 return 200,但真正的 API 调用将return 401(因为令牌现已过期)。

事件流本质上是:

  1. 用户触发预检 API 调用,生成一个 OPTIONS 请求。
  2. Keycloak 的令牌过期并刷新。
  3. 预检请求 returns,使用旧的 Keycloak 令牌发送 GET 调用。
  4. API return 返回 401,因为旧令牌已过期。

在我的浏览器的“网络”选项卡中显示如下:

如何确保 Keycloak 令牌在这些事件之间不会过期?

这是我使用的代码:

async onTokenExpired() {
  this.token = await this.updateToken();
  this.updateHeaders();
}

updateHeaders() {
  http.setHeaders({
    Authorization: `Bearer ${this.token}`
  });
}

updateToken() {
  return new Promise((resolve, reject) => {
    this.keycloak.updateToken()
      .success(() => {
        resolve(this.keycloak.token);
      })
      .error(reject);
  });
}

好的,我最终采用的解决方案包括每次调用 Keycloak 的 updateToken 方法时调用 API,传入 minValidity 20 秒。

updateToken(minValidity)

If the token expires within minValidity seconds (minValidity is optional, if not specified 5 is used) the token is refreshed. If the session status iframe is enabled, the session status is also checked.

Keycloak's updateToken documentation.

我的 API 调用代码现在如下所示:

post(...) {
  this.keycloak.updateToken(20).success(() => {
    fetch(...)
  })
}

在伪代码中,这基本上执行以下操作:

When the post method is called:
  Attempt to update the token if it is going to expire within the next 20 seconds.
  If that is successful (regardless of whether it updated or not), call the API.

我不认为这是一个完美的解决方案,因为我确信可能存在预检请求执行时间超过 20 秒的情况,但是在那种情况下,这并不是问题的真正原因,需要在服务器端解决。如果预检请求的执行时间经常超过 20 秒,则 minValidity 可以增加到更长的持续时间。 20本身就已经很宽松了(默认值为5)。