Spring 启动 OIDC 刷新令牌场景
Spring boot OIDC Refresh token scenario
我们目前正在开发具有微服务架构的应用程序,如下图所示,一切正常fine.However需要对以下几点进行澄清。
- 为了确保 Gateway 和 Deep 微服务之间的通信安全,我们传递 IDToken 并在每个微服务级别对其进行验证,但是一旦 IDtoken 过期服务 returns 401 状态代码,然后在 Ui 我们触发授权流程最终导致整页刷新,如果用户正在提交非常大的表单,那么所有数据都将丢失,而且根据 OIDC 规范,我们无法刷新 ID 令牌,因此不确定如何处理这种情况。
为了克服第一个问题,我们可以将 access_token 传递给微服务而不是 idtoken,但是我们每次都需要调用 /userinfo
端点以从提供商处获取用户信息并考虑高并发性是继续进行的好习惯吗?
或者我们在这里遗漏了一些东西并且有更好的替代方法来解决这个问题?
任何帮助将不胜感激
Spring 在 application.yml 文件中启动 OIDC 属性
security:
oauth2:
client:
registration:
pingIdentity:
scope:
- openid
- profile
- email
- phone
- job_title
- scoped_entitlement
- authorization_group
- entitlement_group
- organizational_data
- basic_start_authorization
client-id: <Client ID>
client-secret: <Client Secret>
provider: pingIdentity
provider:
pingIdentity:
issuer-uri: <Issuer URI>
我认为使用 open id connect 的概念有问题。
Open id connect 不是像 oauth2 那样的 authentication/authorization 协议,它是 oauth2 之上的一层,用于向客户端提供用户信息。
因此,idtoken 中包含的信息的目标受众是尝试使用资源(前端)的应用程序,而不是资源服务器(微服务)。正如你在这里看到的
https://openid.net/specs/openid-connect-core-1_0.html
必须发送到微服务的令牌是与 idtoken 一起颁发的访问令牌,因为这是必须用于授权操作的令牌。
另一个问题是您可能需要用户信息才能在服务中执行某些操作,但这不是同一流程的一部分。
authentication/authorization 流程仅确保一个用户有效并有权在特定资源服务器(微服务)上执行特定操作
如果这样,当auth过程结束后,你需要获取用户信息,我建议你三种可能的解决方案:
您可以使用 jwt 令牌(自编码访问令牌)作为访问令牌而不是不透明的,这样您就可以在子声明中获取用户 ID,并以此查询用户服务获取其他信息。
和第一点一样,你可以使用 jwt acces token 并添加自定义声明来存储额外的用户信息
如果您在 zuul 网关中进行访问令牌验证,您可以在网关中获取用户信息并将自定义 jwt 传递给包含您需要的信息的微服务。此令牌不需要是访问令牌,因为 authentication/authorization 操作已由网关完成。
这样您就可以毫无问题地刷新您的访问令牌
我认为您的关键问题是令牌在用户无法控制的情况下过期。
您可以考虑以下选项。
在您的 SPA 中保留一个循环任务,该任务将检查当前时间和 IDToken 的过期时间。当令牌即将过期时(比如不到 5 分钟),SPA 会提示一个小对话框并要求用户输入她的凭据。提交表单后,新令牌将被接收并替换为 session/local 存储或 cookie。
这样当用户提交表单时,它将使用新令牌。
这不需要比当前服务更多的服务,您只需要 SPA 中的其他功能。
缺点是,用户必须再次输入密码。
如果您可以定义另一个服务来接收 refersh_token 和 IDToken 并存储它,那么 SPA 可以保持定期发送心跳请求。 user/or 用户在本地与页面交互时,可以在页面处于焦点时发送请求。 (例如可以在鼠标 moved/scrolled 等上每 5 分钟发送一次)。
后端服务会检查令牌是否即将过期,然后它会使用刷新令牌获取新令牌,然后将其传递给SPA。 SPA 将在其结束时为后续请求更新令牌。只要用户在页面上工作,所有这一切都将在后台发生,不会打扰用户。
您将不得不处理额外的复杂性以换取用户便利。
我们目前正在开发具有微服务架构的应用程序,如下图所示,一切正常fine.However需要对以下几点进行澄清。
- 为了确保 Gateway 和 Deep 微服务之间的通信安全,我们传递 IDToken 并在每个微服务级别对其进行验证,但是一旦 IDtoken 过期服务 returns 401 状态代码,然后在 Ui 我们触发授权流程最终导致整页刷新,如果用户正在提交非常大的表单,那么所有数据都将丢失,而且根据 OIDC 规范,我们无法刷新 ID 令牌,因此不确定如何处理这种情况。
为了克服第一个问题,我们可以将 access_token 传递给微服务而不是 idtoken,但是我们每次都需要调用
/userinfo
端点以从提供商处获取用户信息并考虑高并发性是继续进行的好习惯吗?或者我们在这里遗漏了一些东西并且有更好的替代方法来解决这个问题?
任何帮助将不胜感激
Spring 在 application.yml 文件中启动 OIDC 属性
security:
oauth2:
client:
registration:
pingIdentity:
scope:
- openid
- profile
- email
- phone
- job_title
- scoped_entitlement
- authorization_group
- entitlement_group
- organizational_data
- basic_start_authorization
client-id: <Client ID>
client-secret: <Client Secret>
provider: pingIdentity
provider:
pingIdentity:
issuer-uri: <Issuer URI>
我认为使用 open id connect 的概念有问题。
Open id connect 不是像 oauth2 那样的 authentication/authorization 协议,它是 oauth2 之上的一层,用于向客户端提供用户信息。
因此,idtoken 中包含的信息的目标受众是尝试使用资源(前端)的应用程序,而不是资源服务器(微服务)。正如你在这里看到的
https://openid.net/specs/openid-connect-core-1_0.html
必须发送到微服务的令牌是与 idtoken 一起颁发的访问令牌,因为这是必须用于授权操作的令牌。
另一个问题是您可能需要用户信息才能在服务中执行某些操作,但这不是同一流程的一部分。
authentication/authorization 流程仅确保一个用户有效并有权在特定资源服务器(微服务)上执行特定操作
如果这样,当auth过程结束后,你需要获取用户信息,我建议你三种可能的解决方案:
您可以使用 jwt 令牌(自编码访问令牌)作为访问令牌而不是不透明的,这样您就可以在子声明中获取用户 ID,并以此查询用户服务获取其他信息。
和第一点一样,你可以使用 jwt acces token 并添加自定义声明来存储额外的用户信息
如果您在 zuul 网关中进行访问令牌验证,您可以在网关中获取用户信息并将自定义 jwt 传递给包含您需要的信息的微服务。此令牌不需要是访问令牌,因为 authentication/authorization 操作已由网关完成。
这样您就可以毫无问题地刷新您的访问令牌
我认为您的关键问题是令牌在用户无法控制的情况下过期。
您可以考虑以下选项。
在您的 SPA 中保留一个循环任务,该任务将检查当前时间和 IDToken 的过期时间。当令牌即将过期时(比如不到 5 分钟),SPA 会提示一个小对话框并要求用户输入她的凭据。提交表单后,新令牌将被接收并替换为 session/local 存储或 cookie。
这样当用户提交表单时,它将使用新令牌。
这不需要比当前服务更多的服务,您只需要 SPA 中的其他功能。
缺点是,用户必须再次输入密码。
如果您可以定义另一个服务来接收 refersh_token 和 IDToken 并存储它,那么 SPA 可以保持定期发送心跳请求。 user/or 用户在本地与页面交互时,可以在页面处于焦点时发送请求。 (例如可以在鼠标 moved/scrolled 等上每 5 分钟发送一次)。
后端服务会检查令牌是否即将过期,然后它会使用刷新令牌获取新令牌,然后将其传递给SPA。 SPA 将在其结束时为后续请求更新令牌。只要用户在页面上工作,所有这一切都将在后台发生,不会打扰用户。
您将不得不处理额外的复杂性以换取用户便利。