如何基于设计加密密码进行身份验证?

How to authenticate based on devise encrypted password?

我有两个 Rails 应用程序使用 devise 进行身份验证:一个网站和一个 API。尽管我是这两个应用程序的所有者,但出于多种原因,我希望将两者完全分开。当用户在网站上注册时,会在 API 端自动创建一个帐户。我遇到的最大问题是让用户 table 在两个应用程序之间保持同步。我最终在网站用户模型上得到了一堆 RESTful API 回调,其中 create/update API 用户。

第二部分是代表登录网站的用户调用API。问题是我没有用户的解密密码,所以我可以拨打 API 电话。所有 API 调用都使用基本 HTTP 身份验证。密码被散列到数据库中,无法解密(这是一件好事,谢谢你的设计)。因为我在两个数据库之间保持所有用户列同步,所以我的网站用户 encrypted_password 列与我的 API 用户 encrypted_password 列相同。

那么,我有什么选择可以解决这个问题?我正在考虑修改 API 以便每次常规调用的管理员调用都需要一个管理员用户名和密码以及一个用户 ID(例如获取该用户的交易)。或者,在这两个应用程序之间实现一个共享数据库——但我在用户和其他模型之间有很多关联……索引如何工作?!或者,劫持设计身份验证并将 encrypted_password(来自我的网站)与 encrypted_password(与我的 API)进行比较 - 因为它们完全相同;但这打开了蠕虫的安全罐。或者,创建密钥身份验证并为用户生成唯一的 GUID……但这与将解密密码存储在数据库中一样糟糕。我讨厌所有这些解决方案。也许有人有更好的主意?

当您在 Devise 中对用户进行身份验证时,它会获取明文密码并将其与胡椒结合并通过 bcrypt 传递。如果加密密码与数据库中的值匹配,则返回记录。

胡椒基于您的 rails 应用机密。因此,除非这两个应用程序具有完全相同的秘密,否则即使您拥有正确的加密密码,身份验证也会失败。请记住,bcrypt 的输入必须相同才能给出相同的结果。这意味着相同的明文、盐、胡椒粉和伸展次数。

你是对的,来回共享密码不是可靠的解决方案。您也是正确的,因为使用 UUID 而不是数字自动递增 id 是解决方案的一部分。

您可以执行自己的身份验证提供程序。 Doorkeeper gem 使设置您自己的 OAuth 提供程序变得非常容易(或者如果可以使用外部服务,您可以使用 Auth0)。

Web 应用程序将使用 Devise + OmniAuth 根据身份验证提供程序对用户进行身份验证,并使用返回的凭据在 Web 应用程序中识别用户。

对于 API 应用程序,我将使用 Knock 进行 JWT 身份验证。 API 服务器通过 oauth gem 代理到您的身份验证服务器。

但是此时您应该考虑您的网站和 API 应用程序是否真的应该 运行 在不同的数据库上。在两个数据库之间保持写入同步可能是一项艰巨的任务,您应该问问自己在这个阶段是否真的需要它。

JWT 可以很容易地在 JWT 中包含用户 ID 等信息,而无需依赖外部持久性,例如用户 table。只需确保令牌已正确签名并且不要在其中存储个人信息(例如电子邮件),因为通常 JWT 不会加密,只会签名。

如果有兴趣的话,我实际上写了一篇关于这个的教程。 https://www.moesif.com/blog/technical/restful-apis/Authorization-on-RESTful-APIs/