Proseguendo da Future Social Authentication Improvements…
Siamo ora nel processo di spostamento di tutte le informazioni relative agli “account associati” in un’unica tabella del database. Questo aiuterà a ridurre significativamente la logica duplicata e consentirà uno sviluppo più rapido in futuro. Ad esempio, la migrazione della nostra logica core di twitter al nuovo sistema ha ridotto il numero di righe di codice da 136 a sole 24
.
Questo post non è progettato per essere un manuale di istruzioni passo-passo per l’aggiunta di un nuovo provider di autenticazione, ma mira a fornire una panoramica, indicando il codice sorgente pertinente ove necessario.
Implementazione di un autenticatore
Ogni autenticatore deve implementare una sottoclasse di Auth::Authenticator. Per utilizzare la nuova logica condivisa, l’autenticatore può invece estendere Auth::ManagedAuthenticator. Un esempio di implementazione essenziale può essere trovato nell’autenticatore Facebook core:
name, enabled? e register_middleware devono essere sovrascritti dalle classi implementanti.
Nota a margine: per la compatibilità multisite, è importante che qualsiasi informazione specifica del sito venga fornita a omniauth in una lambda
setup, anziché essere fissata al momento della definizione. Consulta tutti gli autenticatori core per esempi di questo.
Tutta la logica per collegare gli account esterni agli account Discourse è gestita da Auth::ManagedAuthenticator. Questo si basa sul fatto che il provider omniauth restituisca dati nel formato definito nella loro documentazione. Se è necessaria qualsiasi manipolazione di questi dati, gli Autenticatori possono sovrascrivere il metodo after_authenticate e manipolare l’auth_token come richiesto. Ad esempio, l’autenticatore Twitter core rimuove tutte le informazioni extra dal token:
I dati sono memorizzati nella tabella del database user_associated_accounts. provider_uid, info, credentials e extra sono tutti presi direttamente dai dati restituiti da omniauth.
Una volta definita una classe Authenticator, essa deve essere registrata. Questo deve avvenire presto nel ciclo di vita dell’applicazione e non può avvenire all’interno del metodo after_initialize di un plugin. La registrazione minima può semplicemente contenere un riferimento all’autenticatore. In un plugin, la registrazione può essere eseguita utilizzando la funzione auth_provider. Ad esempio:
auth_provider authenticator: OpenIDConnectAuthenticator.new()
Nel core, la registrazione avviene in discourse.rb. L’elenco completo delle opzioni possibili per AuthProvider può essere trovato qui. Il contenuto testuale può essere definito utilizzando queste opzioni, ma è meglio fornire stringhe localizzabili in client.en.yml seguendo le chiavi standard. Ad esempio:
Note aggiuntive su ManagedAuthenticator di @fantasticfears
ManagedAuthenticator in dettaglio
Potrebbe essere necessario lavorare su qualcosa di speciale per l’autenticazione. E vorresti saperne di più su ManagedAuthenticator. In sostanza, ha diverse operazioni, opzioni e controlla come verranno utilizzati i dati.
Discourse gestisce le informazioni utente con due controller. Users::OmniauthCallbacksController gestisce il payload una volta completata l’autenticazione OAuth2. after_authenticate viene chiamato qui. Anche can_connect_existing_user? viene utilizzato qui.
Ci sono alcuni metodi privati che puoi leggere per capire come funzionano i diversi campi dei dati.
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 ha revoke_account che utilizza can_revoke? e revoke. Ma perché il metodo revoke funzioni in remoto, è necessario costruire la propria implementazione.
UserAuthenticator è una classe di servizio che aiuta a autenticare (verificando la conferma dell’email o il percorso OAuth2) gli utenti. after_create_account viene chiamato qui.
La logica core rimane in after_authenticate con la classe dati Auth::Result. Seguiamo la struttura dei dati qui. extra_data verrà passato a after_create_account per creare i record correlati.
result.extra_data = {
provider: auth_token[:provider],
uid: auth_token[:uid],
info: auth_token[:info],
extra: auth_token[:extra],
credentials: auth_token[:credentials]
}
Tenterà di abbinare e collegarsi a un account esistente.
Potresti chiederti perché la creazione automatica dell’account è possibile ma non c’è User.create. Questo viene fatto in UsersController#create.
authentication = UserAuthenticator.new(user, session)
L’utente è un’istanza nuova che verrà popolata con i dati della sessione preparati dal provider di autenticazione. Fidati di me, è solo magia.
Migrazione al nuovo sistema
Per fornire un passaggio senza interruzioni al nuovo sistema, i dati dovrebbero essere migrati dalla vecchia posizione di archiviazione. Per i provider di autenticazione core, ciò potrebbe comportare tabelle dedicate. Per i plugin, ciò potrebbe comportare plugin_store_rows o oauth2_user_infos. I dati minimi richiesti in una riga di user_associated_accounts sono provider_name, provider_uid e user_id. Per un esempio di migrazione, consulta:
Una volta che il sistema ManagedAuthenticator sarà stato rilasciato sul ramo stabile con la v2.2.0, inizieremo a migrare i plugin di autenticazione ufficiali. A questo punto, verrà aggiunto qui un esempio di migrazione di plugin_store_row.
Questo documento è sotto controllo di versione - suggerisci modifiche su github.