使用 OAuth and/or OpenID 开发 RESTful API
Developing a RESTful API with OAuth and/or OpenID
我正在努力思考如何使用多个外部令牌提供商实施 OAuth 或 OpenID。从我的角度来看,像 google 这样的提供者将两种规范混合在一个 api 中,我在保护资源和处理用户数据的方式上区分了这两种机制。 OpenID 仅用于身份验证,我自己生成 access_tokens 并自己保存所有用户数据,而另一方面 OAuth 提供外部 access_tokens 并管理用户数据。
涉及的实体:
- 外部提供商 - 这是我对 OAuth/OpenID 提供商的称呼,例如 Google OAuth
- 后端 - 主要用作客户端RESTful API的服务器
- 客户端 - 需要访问后端提供的资源的应用程序(例如 SPA、IOS 应用程序、桌面客户端)
我正在为包括网络在内的几种不同类型的客户端开发一个快速后端(rest api),ios/android。根据我的理解,我有以下选项:(指的是我想使用的提供商的大多数实现文档,而不是规范)
选项 1 - OpenID
- 客户通过与任何外部提供商(Apple、Google、Facebook)登录获得 auth_code
- 客户端将此 auth_code 发送到我的后端,此代码用于发出 id_token
- 后端使用此 id_token 对用户进行身份验证并存储有关用户的任何必需信息
- 后端生成一个 access/refresh 令牌用于授权并将其发送回客户端
- 现在我可以使用我的 access_token 进行授权,使用刷新令牌 auth-state-management(注销,使令牌无效)
问题 - 真的有问题吗?
- 我不确定我是否需要经常检查用户是否仍然是 有效 身份。对于有效身份,我的意思是外部身份(例如 google 用户)是否仍然存在,这基本上与我的持久层是否必须使该用户无效(删除)有关。换句话说,我是否必须将我的持久层与外部提供程序同步以避免 dead/unusable 身份。如果电子邮件地址等信息发生变化并且我的后端没有收到通知,这尤其是一个问题。或者我应该接受这样一个事实,即我后端的用户仅通过 ID 与外部用户相关,而客户必须自己在我的后端管理他们的数据(例如,在客户端更改他们的电子邮件)。这意味着我最好忽略对外部用户数据的任何更改(在提供商处)。
选项 2 - OAuth
- 客户通过与任何外部提供商(SiwA(ios)、Google、Facebook)登录获得auth_code
- 客户端将此 auth_code 发送到我的后端,此代码用于从提供商
发出 access_token/refresh_token
- 后端发回从外部提供者
获得的access_token/refresh_token
- 现在每次客户端发出请求时,它都必须包含外部 access_token,然后在后端使用它来询问外部提供者此令牌是否有效以及客户端是否可以访问资源。换句话说,我使用外部 access_token 进行授权
- 每当后端需要用户数据(例如电子邮件、地址...)时,有必要通过提供客户提供的 access_token 向外部提供商请求此数据
Problems/Questions:
- 我假设刷新过程必须在客户端执行,以防后端在令牌过期时未经授权从提供商重定向。对吗?
- 我如何确定令牌来自哪个提供商。实施试错过程并询问每个提供者这是否是有效令牌对我来说似乎很奇怪。例如。如果后端在请求的 header 中收到访问令牌,它不知道要询问哪个提供者。 (或者我应该在 header 中编码此信息,例如
Bearer Provider Token
以便知道在哪里检查访问令牌。
- 使用选项 2,只要外部提供商遇到停机,任何用户都无法使用我的后端,而仅使用 选项 1登录(初始登录或显式注销后,会使刷新令牌无效)不适用于此特定提供商。
有什么我遗漏的吗?在我看来,选项 2 向身份验证提供者引入了很多不必要的通信,而 选项 1 确实忽略了可能需要的任何通信(例如身份状态的同步)?
我的主要问题是,考虑到 Option 1 这似乎更适合我的场景,我是否必须对用户状态的任何状态变化做出反应,比如外部电子邮件的变化提供者或忽略任何东西是否有任何缺点允许身份验证的外部用户 ID。
我最终实现了 OpenID,意识到我只需要身份验证,不需要授权,也不需要用户数据的严格耦合。在提出问题时,我意识到了差异,但是我没有深入研究我的项目的要求。因此我放弃了基本的 OAuth 协议,因为我不需要对外部资源的任何授权。
关于 OpenID,来自 OpenID 提供商的外部身份管理不在协议范围内,必须独立完成。还有其他协议和方法可以解决这个问题,例如SCIM.
我最终依靠 id_token 提供的外部 ID 是唯一的这一事实,并在第一次验证(基本上是注册)时初始化一次性映射。从这一刻起,我的服务器将管理用户数据。随后的身份验证请求依赖于此映射永远不会更改的事实,并且任何用户数据可能与保存在提供者处的任何数据不同,例如与外部身份的 google 邮件相比,我服务器上的不同邮件地址。不过这并不违反我的要求。
此外,我想补充一点,我最终支持隐式流和授权码流,这意味着客户端可以直接发送 id_token,而不是发送 auth_code。我没有完全理解为什么这更不安全,因为从我目前的角度来看,我的服务器要求提供者验证 id_token,它通过提供错误的 id_tokens 来防止任何恶意意图。
我正在努力思考如何使用多个外部令牌提供商实施 OAuth 或 OpenID。从我的角度来看,像 google 这样的提供者将两种规范混合在一个 api 中,我在保护资源和处理用户数据的方式上区分了这两种机制。 OpenID 仅用于身份验证,我自己生成 access_tokens 并自己保存所有用户数据,而另一方面 OAuth 提供外部 access_tokens 并管理用户数据。
涉及的实体:
- 外部提供商 - 这是我对 OAuth/OpenID 提供商的称呼,例如 Google OAuth
- 后端 - 主要用作客户端RESTful API的服务器
- 客户端 - 需要访问后端提供的资源的应用程序(例如 SPA、IOS 应用程序、桌面客户端)
我正在为包括网络在内的几种不同类型的客户端开发一个快速后端(rest api),ios/android。根据我的理解,我有以下选项:(指的是我想使用的提供商的大多数实现文档,而不是规范)
选项 1 - OpenID
- 客户通过与任何外部提供商(Apple、Google、Facebook)登录获得 auth_code
- 客户端将此 auth_code 发送到我的后端,此代码用于发出 id_token
- 后端使用此 id_token 对用户进行身份验证并存储有关用户的任何必需信息
- 后端生成一个 access/refresh 令牌用于授权并将其发送回客户端
- 现在我可以使用我的 access_token 进行授权,使用刷新令牌 auth-state-management(注销,使令牌无效)
问题 - 真的有问题吗?
- 我不确定我是否需要经常检查用户是否仍然是 有效 身份。对于有效身份,我的意思是外部身份(例如 google 用户)是否仍然存在,这基本上与我的持久层是否必须使该用户无效(删除)有关。换句话说,我是否必须将我的持久层与外部提供程序同步以避免 dead/unusable 身份。如果电子邮件地址等信息发生变化并且我的后端没有收到通知,这尤其是一个问题。或者我应该接受这样一个事实,即我后端的用户仅通过 ID 与外部用户相关,而客户必须自己在我的后端管理他们的数据(例如,在客户端更改他们的电子邮件)。这意味着我最好忽略对外部用户数据的任何更改(在提供商处)。
选项 2 - OAuth
- 客户通过与任何外部提供商(SiwA(ios)、Google、Facebook)登录获得auth_code
- 客户端将此 auth_code 发送到我的后端,此代码用于从提供商 发出 access_token/refresh_token
- 后端发回从外部提供者 获得的access_token/refresh_token
- 现在每次客户端发出请求时,它都必须包含外部 access_token,然后在后端使用它来询问外部提供者此令牌是否有效以及客户端是否可以访问资源。换句话说,我使用外部 access_token 进行授权
- 每当后端需要用户数据(例如电子邮件、地址...)时,有必要通过提供客户提供的 access_token 向外部提供商请求此数据
Problems/Questions:
- 我假设刷新过程必须在客户端执行,以防后端在令牌过期时未经授权从提供商重定向。对吗?
- 我如何确定令牌来自哪个提供商。实施试错过程并询问每个提供者这是否是有效令牌对我来说似乎很奇怪。例如。如果后端在请求的 header 中收到访问令牌,它不知道要询问哪个提供者。 (或者我应该在 header 中编码此信息,例如
Bearer Provider Token
以便知道在哪里检查访问令牌。 - 使用选项 2,只要外部提供商遇到停机,任何用户都无法使用我的后端,而仅使用 选项 1登录(初始登录或显式注销后,会使刷新令牌无效)不适用于此特定提供商。
有什么我遗漏的吗?在我看来,选项 2 向身份验证提供者引入了很多不必要的通信,而 选项 1 确实忽略了可能需要的任何通信(例如身份状态的同步)? 我的主要问题是,考虑到 Option 1 这似乎更适合我的场景,我是否必须对用户状态的任何状态变化做出反应,比如外部电子邮件的变化提供者或忽略任何东西是否有任何缺点允许身份验证的外部用户 ID。
我最终实现了 OpenID,意识到我只需要身份验证,不需要授权,也不需要用户数据的严格耦合。在提出问题时,我意识到了差异,但是我没有深入研究我的项目的要求。因此我放弃了基本的 OAuth 协议,因为我不需要对外部资源的任何授权。
关于 OpenID,来自 OpenID 提供商的外部身份管理不在协议范围内,必须独立完成。还有其他协议和方法可以解决这个问题,例如SCIM.
我最终依靠 id_token 提供的外部 ID 是唯一的这一事实,并在第一次验证(基本上是注册)时初始化一次性映射。从这一刻起,我的服务器将管理用户数据。随后的身份验证请求依赖于此映射永远不会更改的事实,并且任何用户数据可能与保存在提供者处的任何数据不同,例如与外部身份的 google 邮件相比,我服务器上的不同邮件地址。不过这并不违反我的要求。
此外,我想补充一点,我最终支持隐式流和授权码流,这意味着客户端可以直接发送 id_token,而不是发送 auth_code。我没有完全理解为什么这更不安全,因为从我目前的角度来看,我的服务器要求提供者验证 id_token,它通过提供错误的 id_tokens 来防止任何恶意意图。