Continuando da Future Social Authentication Improvements…
Siamo ora in fase di migrazione di tutte le informazioni di “account associato” in un’unica tabella di 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 è concepito come un manuale di istruzioni passo passo per aggiungere 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 di base si trova nell’autenticatore Facebook core:
Le classi che implementano devono sovrascrivere name, enabled? e register_middleware.
A margine: per la compatibilità multisito, è importante che qualsiasi informazione specifica del sito venga fornita a omniauth in una lambda
setup, anziché essere fissa al momento della definizione. Vedi tutti gli autenticatori core per gli esempi.
Tutta la logica per collegare gli account esterni agli account Discourse è gestita da Auth::ManagedAuthenticator. Questo si basa sul provider omniauth che restituisce i dati nel formato definito nella loro documentazione. Se è necessaria una manipolazione di questi dati, gli autenticatori possono sovrascrivere il metodo after_authenticate e manipolare il 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 presi direttamente dai dati restituiti da omniauth.
Una volta definita una classe Authenticator, 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 effettuata utilizzando la funzione auth_provider. Ad esempio:
auth_provider authenticator: OpenIDConnectAuthenticator.new()
Nel core, la registrazione avviene in discourse.rb. Un elenco completo delle possibili opzioni di AuthProvider è disponibile qui. Il contenuto di testo 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. Fondamentalmente, 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. Viene utilizzato anche can_connect_existing_user?.
Ci sono alcuni metodi privati che puoi leggere per capire come funzionano i diversi campi 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 affinché il metodo revoke funzioni da remoto, devi creare la tua implementazione.
UserAuthenticator è una classe di servizio che aiuta ad autenticare (verificando la conferma dell’email o il percorso OAuth2) gli utenti. after_create_account viene chiamato qui.
La logica principale 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 la creazione dei 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 trovare corrispondenze e si collegherà 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 è una nuova istanza che verrà popolata dai dati della sessione preparati dal provider di autenticazione. Fidati di me, è solo magia.
Migrazione al nuovo sistema
Per garantire una transizione fluida al nuovo sistema, i dati devono essere migrati dalla vecchia posizione di archiviazione. Per i provider di autenticazione core, questa potrebbe essere una tabella dedicata. Per i plugin, potrebbero essere 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 vedi:
Una volta che il sistema ManagedAuthenticator sarà rilasciato sulla branch stabile con la v2.2.0, inizieremo a migrare i plugin di autenticazione ufficiali. A quel punto, verrà aggiunto qui un esempio di migrazione di plugin_store_row.
Questo documento è controllato tramite versione - suggerisci modifiche su github.