Attivazione di creazione account/login su un servizio esterno quando un utente effettua l'accesso su discourse

Ho un plugin JS sul mio sito Discourse. Questo JS utilizza PocketBase per archiviare dati. PocketBase è un servizio SQLite “serverless” che mi permette di archiviare file e blob JSON. PocketBase ha un fantastico sistema di autenticazione basato su JWT, in modo che una volta che un utente ha un token di autenticazione, può archiviare dati in modo sicuro direttamente in PocketBase (senza passare attraverso un server backend, ecc.) direttamente dal JS sul lato client.

Sto cercando un modo per generare automaticamente un accesso sul lato PocketBase quando un utente accede a Discourse.

Il mio primo tentativo è stato quello di far sì che il plugin JS effettui una chiamata a un percorso sul server e includa i cookie di autenticazione di Discourse. Quindi, per quel percorso, lasciare che nginx lo inoltri a un servizio (“login proxy”) che può decodificare i cookie di autenticazione e determinare chi è l’utente. Con le informazioni utente verificate, il login proxy può quindi effettuare una chiamata speciale a PocketBase e ottenere un cookie di autenticazione PocketBase, e quindi restituire quel cookie di autenticazione PocketBase che il JS lato client può utilizzare per effettuare richieste successive direttamente a PocketBase.

Ma sto avendo problemi a decodificare i cookie di autenticazione di Discourse (immagino che _t sia il cookie giusto, ma non vedo un modo semplice per accedere ai dettagli dell’utente e temo che la struttura possa cambiare comunque).

C’è un modo più intelligente per accedere in modo sicuro all’indirizzo email di un utente connesso? Non penso che questo debba avvenire sul lato client e preferirei farlo sul lato server per ovvie ragioni di sicurezza.

Non conosco abbastanza il tuo stack o il tuo caso d’uso, ma penso di aver risolto un problema simile in passato e alcune idee potrebbero esserti utili.

Ho un’app Next.js in cui ho bisogno che il lato client abbia un JWT valido per effettuare chiamate alla mia API backend se esiste una sessione Discourse.

Per questo utilizzo Discourse come mio provider di identità tramite DiscourseConnect.

Nel mio caso, lo sto facendo con una singola chiamata fetch lato client con { credentials: "include" }, che funziona solo perché ho tutto configurato con un singolo dominio e la chiamata fetch segue in modo trasparente i reindirizzamenti.

Il mio client recupera un /auth/token personalizzato, che verifica l’esistenza di _t (solo per evitare un reindirizzamento inutile altrimenti) e restituisce un reindirizzamento a un URL /session/sso_provider protetto, costruito seguendo la documentazione nell’argomento collegato, con nonce/sso/sig, e un return_sso_url che punta a un /auth/callback personalizzato, che estrarrà i dati inviati da Discourse, costruirà e restituirà un token JWT che il mio client potrà utilizzare d’ora in poi.

Credo che il tuo caso d’uso possa essere risolto in modo simile.

Fantastico, ci proverò. Grazie mille.

1 Mi Piace

@renato Alcune domande, se non ti dispiace.

Ciò significa che devo delegare l’intera gestione dell’autenticazione degli utenti all’app connect? Non sono sicuro di volerlo fare, se è così.

Se connect è solo un ulteriore livello sopra la gestione esistente dell’autenticazione degli utenti di discourse, allora sembra fattibile.

Ma, quando ho iniziato a leggere di discourse connect, temo di dover ora creare e mantenere un’app completamente nuova per la gestione dell’autenticazione degli utenti, e al momento non so davvero come definire l’ambito di questa operazione.

La mia risposta presuppone che tu stia utilizzando Discourse come provider di identità (con le sue interfacce utente di accesso/registrazione) e desideri mantenerlo così.

Sul lato Discourse, abilitarlo è semplice come

Tuttavia, hai menzionato che stai creando un plugin.

Se crei “un percorso sul server” in una nuova azione controller in un plugin Discourse, puoi ottenere l’utente dalla sessione, chiamare terze parti e restituire il JWT al tuo client.

Grazie mille per la discussione.

Ho letto il link: Use Discourse as an identity provider (SSO, DiscourseConnect) - #8 by reverend_paco

Ma penso che questo sia se voglio inviare i miei utenti a un sito secondario e gestire l’autenticazione lì.

Nel mio caso, ho un pezzo di JS che viene eseguito sul sito di Discourse. E voglio che quel JS chiami un percorso sullo stesso server e riceva un cookie per Pocketbase.

In realtà uso un proxy nginx davanti a Discourse, e quindi ho appena aggiunto un percorso speciale /pb/auth (ad esempio). Quando il mio JS raggiunge quel percorso, un server proxy backend (che non è all’interno di Discourse) accetta quella connessione e tenta di decodificare il cookie di sessione _t.

Stavo facendo così perché sembra un po’ più facile che aggiungere un plugin Discourse (ho meno familiarità con quello e con la configurazione di sviluppo, ecc.). Se si tratta semplicemente di decodificare un cookie usando base64 e hashing SHA, ho pensato che mi avrebbe fornito un payload sicuro per dirmi chi è l’utente.

Ma, se pensi che ci sia un modo semplice per creare un plugin che aggiunga questo percorso a Discourse, sono molto interessato a provarlo. Sembra la strada giusta a lungo termine. Ma sono un vecchio programmatore Perl, quindi preferisco la strada pigra, e il mio percorso nginx sembrava più pigro. :slight_smile:

Tutt’altro: se hai un “sito” separato (PocketBase in questo esempio) e vuoi che Discourse sia la fonte di verità per la gestione degli utenti/autenticazione – come il mio esempio Next.js.

Inizierei leggendo

Ottimo, sono entusiasta di leggerlo. Ho iniziato a guardare il plugin scheletro di esempio (GitHub - discourse/discourse-plugin-skeleton: Template for Discourse plugins) e sono rimasto un po’ deluso perché non ha alcuna documentazione.

A prima vista devo chiedere: questo tutorial aggiunge codice all’installazione base di rails per discourse? Va bene farlo se è il modo ufficiale, ma sembra pericoloso e sarebbe meglio gestirlo come un plugin (che può essere facilmente disinstallato, disabilitato). Inoltre, non devo preoccuparmi che questo possa interrompere gli aggiornamenti di discourse se il mio codice non è nel repository di github?

Ad esempio qui:

Questo significa che devo davvero entrare nel container (./launcher enter app) e poi modificare /var/www/app/controllers/snack_controller.rb?

E, in realtà, ho appena seguito quelle istruzioni. Non riesco a far funzionare il percorso /admin/snack.json, anche dopo aver eseguito ./launcher rebuild app.

Questo tutorial sembra avere circa otto anni. È davvero il modo corretto di fare le cose?

Ci sono altre guide, la data in alto è la creazione dell’argomento ma tutto ciò che è in Documentation dovrebbe essere aggiornato – faccelo sapere se trovi problemi.

Puoi controllare il codice del Plugin esistente come riferimento.

No:

Ho l’impressione che questo non sia stato ancora aggiornato

Penso che il file ora sia https://github.com/discourse/discourse/blob/main/app/assets/javascripts/admin/addon/routes/admin-route-map.js
ed è stato rinominato nel 2020.

2 Mi Piace

Ok, ho provato a seguire le istruzioni. Ho provato a usare questo comando rake plugin:create[pocketbase-auth] all’interno del container (dato che rake non sarebbe disponibile all’esterno, giusto). Ma fallisce miseramente perché non ho git configurato all’interno del container.

Come ho letto ulteriormente, sembra che debba specificare il repository git del plugin per visualizzare un plugin nella sezione admin. Tuttavia, non sono ancora arrivato al punto di avere una versione del plugin minimamente funzionante e non ho le cose all’interno di un repository git.

EDIT: Non ho letto attentamente, ed effettivamente questo richiede una configurazione di sviluppo, che è chiaramente indicata fin dall’inizio. Lavorerò su questo e tornerò qui.

Sospetto che queste difficoltà siano dovute al fatto che tipicamente i plugin vengono sviluppati contro una configurazione “dev” di discourse, non all’interno del container docker che sto eseguendo. Va bene, ma vorrei che le guide per sviluppatori di plugin iniziassero con questa premessa e con istruzioni su come eseguire in questo modo. Il modo consigliato per eseguire discourse è usare docker (che adoro), ma penso che ci sia una lacuna tra come eseguire le cose all’interno di docker e fare sviluppo all’interno delle guide.

# rake plugin:create[pocketbase-auth]
Cloning 'https://github.com/discourse/discourse-plugin-skeleton' in '/var/www/discourse/plugins/pocketbase-auth'...
Initializing git repository...
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint: 
hint: 	git config --global init.defaultBranch <name>
hint: 
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint: 
hint: 	git branch -m <name>
Initialized empty Git repository in /var/www/discourse/plugins/pocketbase-auth/.git/
Author identity unknown

*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.
fatal: unable to auto-detect email address (got 'discourse@community-public-do-vm-app.(none)')
rake aborted!
Command failed with exit 128: git
/var/www/discourse/lib/tasks/plugin.rake:356:in `system'
/var/www/discourse/lib/tasks/plugin.rake:356:in `block (2 levels) in <main>'
/var/www/discourse/lib/tasks/plugin.rake:346:in `chdir'
/var/www/discourse/lib/tasks/plugin.rake:346:in `block in <main>'
/usr/local/bin/bundle:25:in `load'
/usr/local/bin/bundle:25:in `<main>'
Tasks: TOP => plugin:create
(See full trace by running task with --trace)

Un aggiornamento: ho seguito il tuo consiglio e ho sviluppato un plugin. Funziona benissimo e fa esattamente quello di cui avevo bisogno. Grazie per il tuo aiuto.

1 Mi Piace

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.