如何实现多后端服务和解耦架构的单点登录
How to implement SSO with multi back-end services and decoupled architecture
背景:
有几个服务(spring 引导 REST API 服务和一些其他使用 REST 的产品 API)作为后端和一些 angular 应用程序(一些 web不同二级域名的站点)作为前端。
一个前端应用可以通过异步的方式调用一些后端服务(通过反向代理在同一个域下,不存在CORS问题)。
目标
SSO,即。如果用户成功登录前端应用程序,则用户无需再次登录即可访问其他应用程序。 (当然,在启用cookie的同一浏览器中)
问题
- REST API 应该遵循客户端凭据流(return 401 如果未通过身份验证)还是身份验证代码流(return 302 如果未通过身份验证)?
许多 documents/tips/posts 建议 REST API 应该遵循客户端凭证流程,因为它是无状态的并且不知道重定向 uri。但是,如果我没记错的话,不可能使用客户端凭证流来实现 OSS,否则所有后端服务都应该是 keycloak 中可以共享 client_id
和 client_secret
.[=15 的同一个客户端=]
如果使用Authentication Code Flow,问题是前端如何在用户成功登录后获取响应数据。这个过程是这样的:
front-end back-end keycloak
| -- asyn call --> |
| <-- HTTP 302 -- |
| -- redirect to login page --> |
| <-- redirect to where ???-- |
如果问题 1 的答案遵循客户端凭证流程,那么在多个后端服务之间共享相同的 client_id
和 client_secret
是否是最佳做法?或者还有其他解决方案吗?
如果问题2的答案是按照Authentication Code Flow,那么登录成功后如何处理异步REST API调用?
1.) SSO 协议
应使用 Open ID Connect
。理论上也有 SAML
,但那个是为 Web 应用程序指定的,而不是为 SPA apps/REST APIs.
2.) 前端(SPA 应用程序)管理身份验证
您需要用户身份,因此客户端凭据流不正确。你需要Authorization Code Flow with Proof Key for Code Exchange (PKCE)
。使用成熟的(OIDC 认证的)库(例如 https://github.com/damienbod/angular-auth-oidc-client),它们将管理一切(令牌刷新、路由授权、注销……)。您不需要任何名称中带有 Keycloak 的库(OIDC 是标准,必须实施,而不是 Keycloak)。 Fronted 为每个 API 请求添加访问令牌(例如使用 Angular 拦截器)。
3.) 后端 (REST APIs) 只需验证令牌
来自前端的调用是 XMLHttpRequest
请求 - 它们在后台。有 302 响应(重定向到 auth)没有意义。用户将无法看到它,所以这就是为什么应该返回 401 Unauthorized
的原因(然后前端可以有自己的业务逻辑来处理它——例如重定向到 auth)。所以后端不需要实现任何登录流程。他们只验证请求中使用的令牌的有效性。最终,他们进行授权,例如只有具有某些特定 groups/roles 的用户才能执行相同的操作 - 只有编辑才能编辑,只有管理员才能删除,否则使用正确的响应代码进行响应 - 403 Forbidden
.
背景:
有几个服务(spring 引导 REST API 服务和一些其他使用 REST 的产品 API)作为后端和一些 angular 应用程序(一些 web不同二级域名的站点)作为前端。
一个前端应用可以通过异步的方式调用一些后端服务(通过反向代理在同一个域下,不存在CORS问题)。
目标
SSO,即。如果用户成功登录前端应用程序,则用户无需再次登录即可访问其他应用程序。 (当然,在启用cookie的同一浏览器中)
问题
- REST API 应该遵循客户端凭据流(return 401 如果未通过身份验证)还是身份验证代码流(return 302 如果未通过身份验证)?
许多 documents/tips/posts 建议 REST API 应该遵循客户端凭证流程,因为它是无状态的并且不知道重定向 uri。但是,如果我没记错的话,不可能使用客户端凭证流来实现 OSS,否则所有后端服务都应该是 keycloak 中可以共享 client_id
和 client_secret
.[=15 的同一个客户端=]
如果使用Authentication Code Flow,问题是前端如何在用户成功登录后获取响应数据。这个过程是这样的:
front-end back-end keycloak
| -- asyn call --> |
| <-- HTTP 302 -- |
| -- redirect to login page --> |
| <-- redirect to where ???-- |
如果问题 1 的答案遵循客户端凭证流程,那么在多个后端服务之间共享相同的
client_id
和client_secret
是否是最佳做法?或者还有其他解决方案吗?如果问题2的答案是按照Authentication Code Flow,那么登录成功后如何处理异步REST API调用?
1.) SSO 协议
应使用Open ID Connect
。理论上也有 SAML
,但那个是为 Web 应用程序指定的,而不是为 SPA apps/REST APIs.
2.) 前端(SPA 应用程序)管理身份验证
您需要用户身份,因此客户端凭据流不正确。你需要Authorization Code Flow with Proof Key for Code Exchange (PKCE)
。使用成熟的(OIDC 认证的)库(例如 https://github.com/damienbod/angular-auth-oidc-client),它们将管理一切(令牌刷新、路由授权、注销……)。您不需要任何名称中带有 Keycloak 的库(OIDC 是标准,必须实施,而不是 Keycloak)。 Fronted 为每个 API 请求添加访问令牌(例如使用 Angular 拦截器)。
3.) 后端 (REST APIs) 只需验证令牌
来自前端的调用是 XMLHttpRequest
请求 - 它们在后台。有 302 响应(重定向到 auth)没有意义。用户将无法看到它,所以这就是为什么应该返回 401 Unauthorized
的原因(然后前端可以有自己的业务逻辑来处理它——例如重定向到 auth)。所以后端不需要实现任何登录流程。他们只验证请求中使用的令牌的有效性。最终,他们进行授权,例如只有具有某些特定 groups/roles 的用户才能执行相同的操作 - 只有编辑才能编辑,只有管理员才能删除,否则使用正确的响应代码进行响应 - 403 Forbidden
.