承接自 Future Social Authentication Improvements…
我们目前正在将所有“关联账户”信息迁移到一个单一的数据库表中。这将有助于显著减少重复的逻辑,并允许未来更快速的开发。例如,将我们的核心 Twitter 逻辑迁移到新系统迁移我们的核心 Twitter 逻辑后,代码行数从 136 行减少到仅 24 行
。
此帖子并非旨在成为添加新身份验证提供程序的逐步操作手册,但它将旨在提供一个概述,并在必要时指向相关的源代码。
实现一个身份验证器
每个身份验证器必须实现 Auth::Authenticator 的一个子类 Auth::Authenticator。要使用新的共享逻辑,身份验证器可以扩展 Auth::ManagedAuthenticator。可以在核心 Facebook 身份验证器中找到一个基本实现的示例:
实现类必须重写 name、enabled? 和 register_middleware。
附注: 为了兼容多站点,重要的是任何特定于站点的 信息 都在
setuplambda 中提供给 omniauth,而不是在定义时固定。请参阅所有核心身份验证器以获取此类示例。
所有将外部账户链接到 Discourse 账户的逻辑都由 Auth::ManagedAuthenticator 处理。这依赖于 omniauth 提供商返回的数据格式,该格式在其文档中定义。如果需要对这些数据进行任何操作,身份验证器可以覆盖 after_authenticate 方法,并根据需要操作 auth_token。例如,核心 Twitter 身份验证器会从 token 中删除所有 extra 信息:
数据存储在 user_associated_accounts 数据库表中。provider_uid、info、credentials 和 extra 都直接取自 omniauth 返回的数据。
定义了 Authenticator 类后,需要对其进行注册。这必须在应用程序生命周期的早期发生,并且不能发生在插件的 after_initialize 方法中。最小的注册可以只包含对身份验证器的引用。在插件中,可以使用 auth_provider 函数进行注册。例如:
auth_provider authenticator: OpenIDConnectAuthenticator.new()
在核心代码中,注册发生在 discourse.rb 中。可以在此处找到 AuthProvider 选项的完整列表。可以使用这些选项定义文本内容,但最好在 client.en.yml 中提供可本地化的字符串,遵循标准键。例如:
来自 @fantasticfears 的其他 ManagedAuthenticator 注释
ManagedAuthenticator 详解
您可能需要处理一些特殊情况的身份验证。并且您想了解更多关于 ManagedAuthenticator 的信息。基本上,它有几个操作、选项,并控制数据的用法。
Discourse 使用两个控制器管理用户信息。Users::OmniauthCallbacksController 在 OAuth2 身份验证完成后管理有效载荷。此时会调用 after_authenticate。can_connect_existing_user? 也会在这里使用。
您可以阅读一些私有方法来了解不同的数据字段是如何工作的。
if authenticator.can_connect_existing_user? && current_user
@auth_result = authenticator.after_authenticate(auth, existing_account: current_user)
else
@auth_result = authenticator.after_authenticate(auth)
end
UsersController 有 revoke_account,它使用 can_revoke? 和 revoke。但要使 revoke 方法能够远程工作,您需要构建自己的实现。
UserAuthenticator 是一个帮助身份验证(验证电子邮件确认或 OAuth2 路径)用户的服务类。after_create_account 在此处调用。
核心逻辑保留在 after_authenticate 中,使用 Auth::Result 数据类。我们遵循这里的数据结构。extra_data 将传递给 after_create_account 以创建相关记录。
result.extra_data = {
provider: auth_token[:provider],
uid: auth_token[:uid],
info: auth_token[:info],
extra: auth_token[:extra],
credentials: auth_token[:credentials]
}
它将尝试匹配并连接到现有账户。
您可能想知道为什么可以自动创建账户,但没有 User.create。这在 UsersController#create 中完成。
authentication = UserAuthenticator.new(user, session)
user 是一个新实例,将由身份验证提供程序准备的会话数据填充。相信我,这只是魔法。
迁移到新系统
为了向新系统实现无缝切换,数据应从旧的存储位置迁移。对于核心身份验证提供程序,这可能是专用的表。对于插件,这可能是 plugin_store_rows 或 oauth2_user_infos。user_associated_accounts 行中所需的最小数据是 provider_name、provider_uid 和 user_id。有关迁移示例,请参阅:
一旦 ManagedAuthenticator 系统在 v2.2.0 版本中发布到稳定分支,我们将开始迁移官方身份验证插件。届时,将在此处添加 plugin_store_row 迁移示例。
本文档已版本控制 - 在 github 上建议更改。