英文:
Spring boot OIDC Refresh token scenario
问题
以下是翻译好的部分:
我们目前正在开发一个具有微服务架构的应用程序,其组件如下图所示,一切都运行正常。然而,对以下几点需要进行一些澄清。
-
为了保护网关与深层微服务之间的通信,我们正在传递IDToken并在每个微服务级别对其进行验证。然而,一旦IDToken过期,服务将返回401状态代码,然后在用户界面上触发授权流程,最终导致整个页面刷新,如果用户在提交非常大的表单时处于中间状态,则所有数据都将丢失。此外,根据OIDC规范,我们无法刷新IDToken,因此不确定如何处理这种情况。
-
为了解决第一个问题,我们可以传递access_token到微服务,而不是IDToken,但是我们每次都需要调用
/userinfo
端点来从提供者获取用户信息,考虑到高并发,这样做是否是一个好的实践? -
或者我们在这里遗漏了什么,有更好的替代方法来解决这个问题吗?
非常感谢任何帮助!
application.yml文件中的Spring Boot 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>
请注意,我只提供了翻译的内容,不包含其他回答或指示。如果您有任何其他需要翻译的内容,请随时提问。
英文:
We are currently working on application having micro-service architecture with following components as shown in below image and everything is working fine.However need some clarification on following points.
-
To secure communication between Gateway and Deep microservice we are passing IDToken and validating it at each microservice level however once IDtoken expires service returns 401 status code and then on Ui we trigger authorization flow which eventually results in full page refresh and if user in middle of submitting very large form then all the data will be lost moroever as per OIDC specificition we can't refresh ID token so not sure how to handle this scenario.
-
To overcome first problem we could pass access_token to microservice rather than idtoken however we need to call
/userinfo
end point each time for getting user information from provider and considering high concurrency is it a good practice to proceed with ? -
Or we are missing something here and there are better alternatives to fix this problem ?
Any help would be much appreciated
Spring boot OIDC Properties in application.yml file
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>
答案1
得分: 2
我认为在使用 OpenID Connect 时存在概念问题。
OpenID Connect 并不像 OAuth 2.0 那样是一个身份验证/授权协议,而是在 OAuth 2.0 的基础上提供用户信息给客户端的一种层次。
所以,idtoken 中包含的信息的预期受众是试图消费资源(前端)的应用程序,而不是资源服务器(微服务)。你可以在这里看到:
https://openid.net/specs/openid-connect-core-1_0.html
必须发送给微服务的令牌是与 idtoken 一起颁发的访问令牌,因为这是必须用于授权操作的令牌。
另一个问题是,你可能需要用户信息来执行服务中的某些操作,但这不属于同一流程。
身份验证/授权流程只确保某个用户是有效的,并且具有在特定资源服务器(微服务)上执行某些操作的特权。
如果在身份验证过程结束后需要获取用户信息,我建议你有三种可能的解决方案:
-
你可以使用 JWT 令牌(自编码的访问令牌)作为访问令牌,而不是使用不透明的令牌,这样你可以在 sub 声明中获取用户ID,并借此查询用户服务以获取其他信息。
-
与第一点类似,你可以使用 JWT 访问令牌,并额外添加自定义声明来存储附加的用户信息。
-
如果你在 Zuul 网关中进行访问令牌验证,你可以在网关中获取用户信息,并使用所需信息向微服务传递自定义 JWT。这个令牌不需要是访问令牌,因为身份验证/授权操作已由网关完成。
通过这种方式,你可以轻松刷新访问令牌,而不会有问题。
英文:
I think there is a problem of concept using open id connect.
Open id connect is not an authentication/authorization protocol as oauth2, it is a layer on top of oauth2 to provide user information to a client.
So the intended audience for the information contained in an idtoken is the application which is trying to consume a resource (frontend) and not the resource server (microservice). As you can see here
https://openid.net/specs/openid-connect-core-1_0.html
The token that must be send to the microservice is the access token that is issued along with the idtoken, because this is the token that must be used to authorize the action.
Other problem is that you may need user information to perform some action in the service but this is not part of the same flow.
The authentication/authorization flow only assures that one user is valid and has privileges to do certain action on certain resource server(microservice)
If then, when the auth proceess has ended, you need to obtain user information, I suggest you three possible solutions:
-
you can use a jwt token (self encoded access token) as access token instead of an opaque one, so you can obtain the user id in sub claim, and with that, query the user service to obtain the other information.
-
Like the point one, you can use jwt acces token and in addition add custom claims to store additional user information
-
if you are doing the acces token validation in zuul gateway, you can get user information in the gateway and pass a custom jwt to the microservices with the info you need. This token does not need to be an access token because the authentication/authorization operation has been done by the gateway.
This way you can refresh your access tokens without problem
答案2
得分: 1
我认为您的关键问题是令牌在没有用户控制的情况下过期了。
您可以考虑以下选项。
-
在您的单页应用程序中保持一个定期任务,该任务将当前时间与IDToken的过期时间进行比较。当令牌即将过期(比如在不到5分钟内),单页应用程序将提示一个小对话框,要求用户输入其凭据。一旦表单提交,新的令牌将被获取并替换在会话/本地存储或者Cookie中。
这样,当用户提交表单时,将会使用新的令牌。
这不需要任何额外的服务,只需在单页应用程序中添加附加功能。
这种方法的缺点是用户需要重新输入密码。
-
如果您可以定义另一个服务来接收refresh_token和IDToken,并将其存储起来,那么单页应用程序可以定期发送心跳请求。请求可以在用户将页面置于焦点或者用户在页面上进行交互时发送(例如,可以在鼠标移动/滚动等操作时每5分钟发送一次)。
后端服务将检查令牌是否即将过期,然后使用刷新令牌来获取新的令牌,然后传递给单页应用程序。单页应用程序将在其端更新令牌,以供后续请求使用。只要用户在页面上操作,所有这些都将在后台进行,不会打扰用户。
您将不得不处理额外的复杂性,以换取用户的便利。
英文:
I think your key issue is token getting expired without any control from the user.
You may consider following options.
-
Keep a recurring task in your SPA which will check current time with the expiration time of the IDToken. When the token is about to expire (Say in less than 5 minutes), SPA would prompt a small dialog and ask the user to input her credentials. Once the form is submitted, the new token will be received and replaced in the session/local storage or cookie.
This way when the user submits the form, it will be with the new token.
This will not need any additional service than current ones and you just need additional function in the SPA.
Downside of this is, user has to enter the password again.
-
If you can define another service to receive the refersh_token along with the IDToken and store it, then the SPA can keep sending heartbeat requests at regular interval. The request can be sent while the page is in focus by the user/or user is interacting with the page locally. (e.g. can be sent every 5 minutes on mouse moved/scrolled etc.).
The backend service will check if the token is about to expire, then it will use refresh token to get the new token and then pass it to SPA. SPA will update the token for subsequent requests at its end. All this will happen in the background without disturbing the user as long as she is working on the page.
You will have to deal with additional complexity in exchange of user convenience.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论