基于 OAuth2 的单点登录

Single sign on based on OAuth2

本人基于OAuth2开发SSO系统

我有 3 个服务:

  1. 包含用户和 OAuth2 服务器的 SSO 身份提供者 - http://sso.idp.loc

  2. 前端部分在 Angular - http://sso.sp-angular.loc

  3. 上的 SSO 服务提供商
  4. SSO 服务提供商(休闲网站)- http://sso.sp-web.loc

服务提供商检查身份提供商发出的每个请求访问令牌。

接下来是机制:

  1. 转到任何服务提供商并按登录
  2. 重定向到 sso.idp.loc/login_check 以检查凭据(来自 cookie)。
  3. 如果未授权 - 转到 sso.idp.loc/login.
  4. 登录后 - 为身份提供者设置 cookie,并在 get 参数中使用这些 cookie 重定向到目标服务提供者。
  5. 从服务提供商的获取参数中设置新的 cookie 并重定向到目标路径。
  6. 如果服务提供商的身份验证突然失败 - 使用目标路径转到 sso.idp。loc/login_check。

Cookie 包含 oauth 访问和令牌。

只要访问令牌有效,一切都很好。 一旦访问令牌过期,服务提供者将转到 sso.idp.loc/login_check 并再次检查访问令牌,然后尝试使用刷新令牌获取新的一次。 如果成功,则新凭据将设置为 sso.idp.loc 和服务提供商。 假设发生在 sso.sp-web.loc.

这里我有几个问题:

  1. 然后另一个服务提供者sso.sp-angular.loc不知道凭据被更改,下一个请求将重定向到sso.idp.loc/login_check(可以整理通过第二次发送请求)。
  2. 当用户在 sso.sp-web.loc 上编辑表单并且令牌已过期时提交将失败。
  3. 如何在令牌过期时管理 ajax 调用?

应该考虑访问令牌可以随时更改的事实。

可能是我的系统出了问题。 我很乐意在这里提供任何解决方案。

您似乎已经实现了 OAuth 2.0 的隐式授权类型。那是很没有安全感的。理想情况下,您应该实施授权代码授权类型并在资源服务器(您称为服务提供商)端维护您的客户端机密。我建议你阅读答案 here and here.

现在让我们回答问题:

  1. 如果你正确设置了cookie的domain属性,第一个资源服务器设置的cookie也应该对第二个服务器可用。

  2. 当用户正在编辑表单并且token过期时,资源服务器中的api过滤器可以检测到过期的token和return 401响应代码给客户端。收到 401 后,客户端或浏览器可以在服务器中进行另一个 api 调用以更新访问令牌。 api 将从 cookie 中获取刷新令牌,并使用客户端密码和刷新令牌调用授权服务器以获取新的访问令牌。如果刷新令牌未过期,授权服务器将 return 一对新的访问和刷新令牌,该令牌将 return 发送到浏览器和 cookie 集。浏览器现在将使用新的访问令牌再次调用表单提交 api。所有这些都将无缝地发生在用户身上。仅当刷新令牌过期时才会发生完全失败。

  3. 同2.

我认为您的 SSO 概念有缺陷 - 您不应该共享相同的令牌。每个客户端(应用程序)的令牌应该不同。 OAuth2 SSO 通常通过以下方式实现(OAuth2 RFC 未涵盖该实现):

  1. 应用程序 "App1" 通过将用户的浏览器重定向到授权服务器(/auth 端点)来请求令牌。
  2. 授权服务器向浏览器设置一个会话 cookie,并保留有关哪个用户在该会话中通过身份验证的信息。 cookie 仅对授权服务器请求有效。
  3. 当另一个应用程序 "App2" 请求令牌时,浏览器会发送会话 cookie 以及 /auth 端点请求。授权服务器解析会话。会话已经过身份验证,因此授权服务器可能会决定不要求提供凭据并立即释放新令牌(或授权代码)。