Continuando desde Future Social Authentication Improvements…
Ahora estamos en proceso de mover toda la información de ‘cuenta asociada’ a una única tabla de base de datos. Esto ayudará a reducir significativamente la lógica duplicada y permitirá un desarrollo más rápido en el futuro. Por ejemplo, migrar nuestra lógica central de Twitter al nuevo sistema redujo el número de líneas de código de 136 a solo 24
.
Esta publicación no está diseñada para ser un manual de instrucciones paso a paso para agregar un nuevo proveedor de autenticación, pero tiene como objetivo proporcionar una descripción general, señalando el código fuente relevante cuando sea necesario.
Implementación de un autenticador
Cada autenticador debe implementar una subclase de Auth::Authenticator. Para usar la nueva lógica compartida, el autenticador puede extender Auth::ManagedAuthenticator. Un ejemplo de una implementación básica se puede encontrar en el autenticador central de Facebook:
Las clases que implementan deben anular name, enabled? y register_middleware.
Aparte: para la compatibilidad con múltiples sitios, es importante que cualquier información específica del sitio se proporcione a omniauth en una lambda
setup, en lugar de fijarse en el momento de la definición. Consulte todos los autenticadores principales para ver ejemplos de esto.
Toda la lógica para vincular cuentas externas a cuentas de Discourse es manejada por Auth::ManagedAuthenticator. Esto se basa en que el proveedor omniauth devuelva datos en el formato definido en su documentación. Si se requiere alguna manipulación de estos datos, los autenticadores pueden anular el método after_authenticate y manipular el auth_token según sea necesario. Por ejemplo, el autenticador central de Twitter elimina toda la información extra del token:
Los datos se almacenan en la tabla de la base de datos user_associated_accounts. provider_uid, info, credentials y extra se toman directamente de los datos devueltos por omniauth.
Una vez que se ha definido una clase Authenticator, debe registrarse. Esto debe ocurrir temprano en el ciclo de vida de la aplicación y no puede ocurrir dentro del método after_initialize de un plugin. El registro mínimo puede contener simplemente una referencia al autenticador. En un plugin, el registro se puede realizar utilizando la función auth_provider. Por ejemplo:
auth_provider authenticator: OpenIDConnectAuthenticator.new()
En el núcleo, el registro tiene lugar en discourse.rb. Una lista completa de las posibles opciones de AuthProvider se puede encontrar aquí. El contenido de texto puede definirse utilizando estas opciones, pero es mejor proporcionar cadenas localizables en client.en.yml siguiendo las claves estándar. Por ejemplo:
Notas adicionales de ManagedAuthenticator por @fantasticfears
ManagedAuthenticator en detalle
Es posible que necesite trabajar en algo especial para la autenticación. Y le gustaría saber más sobre ManagedAuthenticator. Básicamente, tiene varias operaciones, opciones y controla cómo se utilizarán los datos.
Discourse administra la información del usuario con dos controladores. Users::OmniauthCallbacksController administra la carga útil una vez que se completa la autenticación OAuth2. after_authenticate se llama aquí. can_connect_existing_user? también se utiliza aquí.
Hay algunos métodos privados que puede leer para comprender cómo funcionan los diferentes campos de datos.
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 tiene revoke_account que utiliza can_revoke? y revoke. Pero para que el método revoke funcione de forma remota, debe crear su propia implementación.
UserAuthenticator es una clase de servicio que ayuda a autenticar (verificar la confirmación del correo electrónico o la ruta OAuth2) a los usuarios. after_create_account se llama aquí.
La lógica central permanece en after_authenticate con la clase de datos Auth::Result. Seguimos la estructura de datos aquí. extra_data se pasará a after_create_account para crear registros relacionados.
result.extra_data = {
provider: auth_token[:provider],
uid: auth_token[:uid],
info: auth_token[:info],
extra: auth_token[:extra],
credentials: auth_token[:credentials]
}
Intentará hacer coincidir y conectarse a una cuenta existente.
Quizás se pregunte por qué es posible la creación automática de cuentas, pero no hay User.create. Esto se hace en UsersController#create.
authentication = UserAuthenticator.new(user, session)
El usuario es una nueva instancia que se completará con los datos de la sesión que prepara el proveedor de autenticación. Créame, es pura magia.
Migración al nuevo sistema
Para proporcionar una transición fluida al nuevo sistema, los datos deben migrarse desde la ubicación de almacenamiento anterior. Para los proveedores de autenticación principales, esto pueden ser tablas dedicadas. Para los plugins, esto pueden ser plugin_store_rows u oauth2_user_infos. Los datos mínimos requeridos en una fila de user_associated_accounts son provider_name, provider_uid y user_id. Para un ejemplo de migración, consulte:
Una vez que el sistema ManagedAuthenticator se haya lanzado a la rama estable con la versión v2.2.0, comenzaremos a migrar los plugins de autenticación oficiales. En ese momento, se agregará un ejemplo de migración de plugin_store_row aquí.
Este documento está controlado por versiones: sugiera cambios en github.