Crea un link di accesso a DiscourseConnect

:bookmark: Questa documentazione spiega come creare collegamenti su un sito provider DiscourseConnect che effettuano l’accesso degli utenti a Discourse e li reindirizzano a un URL Discourse specifico.

:person_raising_hand: Livello utente richiesto: Amministratore

I siti che utilizzano DiscourseConnect possono aggiungere collegamenti sul loro sito provider DiscourseConnect che effettueranno l’accesso degli utenti a Discourse e li reindirizzeranno a un URL Discourse specifico. Ciò si ottiene creando collegamenti che puntano alla rotta /session/sso e che hanno un parametro return_path impostato sul percorso della pagina Discourse in cui si desidera che gli utenti finiscano.

La proprietà href del collegamento dovrebbe avere il formato seguente, con il percorso in cui si desidera che gli utenti finiscano sostituito da \u003crelative_path\u003e:

https://forum.example.com/session/sso?return_path=\u003crelative_path\u003e

Un esempio di tag di ancoraggio che effettuerà l’accesso a un utente e lo reindirizzerà alla homepage del sito Discourse:

\u003ca href=\"https://forum.example.com/session/sso?return_path=/\"\u003eCommunity\u003c/a\u003e

Un esempio di tag di ancoraggio che effettuerà l’accesso a un utente e lo reindirizzerà alla pagina Argomenti Principali:

\u003ca href=\"https://forum.example.com/session/sso?return_path=/top\"\u003eTop Topics\u003c/a\u003e

Come viene memorizzato il return_path su Discourse

Discourse memorizza il valore del parametro return_path nella sessione del server, indicizzato dal nonce SSO che viene generato quando un utente visita la rotta /session/sso. Alla fine del processo di autenticazione DiscourseConnect, Discourse cerca il return_path utilizzando il nonce e reindirizza gli utenti a tale percorso.

Rendere il processo trasparente per gli utenti autenticati

Quando un utente visita la rotta /session/sso di Discourse, viene reindirizzato all’URL impostato dall’impostazione del sito discourse connect url. Il provider DiscourseConnect gestirà quindi il processo di autenticazione nello stesso modo in cui farebbe se l’utente avesse cliccato sul pulsante \u003cbutton\u003eLogin\u003c/button\u003e di Discourse.

Affinché il processo di autenticazione sia trasparente per gli utenti che hanno già effettuato l’accesso al sito del provider di autenticazione, il codice DiscourseConnect del provider di autenticazione deve verificare se l’utente ha effettuato l’accesso o meno. Se l’utente non ha effettuato l’accesso, si procede con il processo di accesso dei provider di autenticazione. Se l’utente ha già effettuato l’accesso, si salta il processo di accesso sul sito del provider di autenticazione.

Ecco un esempio commentato, che utilizza il codice del plugin WP Discourse. Dimostra come gli utenti autenticati possano essere gestiti diversamente dagli utenti non autenticati:

public function sso_parse_request( $wp ) {
    // Verifica se il Single Sign-On (SSO) è abilitato nelle opzioni del plugin
    if ( empty( $this-\u003eoptions['enable-sso'] ) ) {
        return null;
    }

    // Gestisce eventuali richieste di logout prima di procedere con l'SSO
    $this-\u003ehandle_logout_request();

    // Verifica se i parametri 'sso' e 'sig' esistono nelle variabili di query
    if ( array_key_exists( 'sso', $wp-\u003equery_vars ) \u0026\u0026 array_key_exists( 'sig', $wp-\u003equery_vars ) ) {
        // Sanifica il payload 'sso' e la firma per garantire che siano sicuri da usare
        $payload = sanitize_text_field( $wp-\u003equery_vars['sso'] );
        $sig     = sanitize_text_field( $wp-\u003equery_vars['sig'] );

        // Se l'utente non ha effettuato l'accesso a WordPress, reindirizza alla pagina di login
        // Questo assicura che gli utenti senza una sessione attiva vengano prima invitati ad accedere a WordPress
        if ( ! is_user_logged_in() ) {
            // Costruisce un URL a cui reindirizzare dopo l'accesso
            $redirect = add_query_arg( $payload, $sig );
            // Genera l'URL di login di WordPress con il parametro di reindirizzamento
            $login    = wp_login_url( esc_url_raw( $redirect ) );

            // Innesca un'azione prima del reindirizzamento al login (opzionale per il logging o azioni personalizzate)
            do_action( 'wpdc_sso_before_login_redirect', $redirect, $login );

            // Reindirizza alla pagina di login di WordPress
            return $this-\u003eredirect_to( $login );
        } else {
            // Se l'utente è già autenticato in WordPress, salta il processo di login
            // e procedi con la validazione del payload e della firma SSO.
            $sso_secret = $this-\u003eoptions['sso-secret'];
            $sso        = new SSO( $sso_secret );
            
            // Valida il payload e la firma utilizzando il segreto SSO
            if ( ! ( $sso-\u003evalidate( $payload, $sig ) ) ) {
                // Gestisce le richieste SSO non valide
                return $this-\u003ehandle_error( 'parse_request.invalid_sso' );
            }

            // Ottiene l'utente WordPress attualmente loggato
            $current_user = wp_get_current_user();
            // Prepara i parametri SSO utilizzando i dati dell'utente loggato
            $params       = $this-\u003eget_sso_params( $current_user );

            try {
                // Genera un nonce dal payload e costruisce la stringa di login SSO
                $params['nonce'] = $sso-\u003eget_nonce( $payload );
                $q               = $sso-\u003ebuild_login_string( $params );
            } catch ( \\Exception $e ) {
                // Gestisce le eccezioni in caso di problemi con la generazione dei parametri SSO
                return $this-\u003ehandle_error( 'parse_request.invalid_sso_params', array( 'message' =\u003e esc_html( $e-\u003egetMessage() ) ) );
            }

            // Innesca un'azione prima di reindirizzare l'utente per il login SSO (utile per il logging)
            do_action( 'wpdc_sso_provider_before_sso_redirect', $current_user-\u003eID, $current_user );

            // Registra il successo dell'SSO se il logging dettagliato è abilitato
            if ( ! empty( $this-\u003eoptions['verbose-sso-logs'] ) ) {
                $this-\u003elogger-\u003einfo( 'parse_request.success', array( 'user_id' =\u003e $current_user-\u003eID ) );
            }

            // Reindirizza l'utente autenticato all'URL di login DiscourseConnect con la stringa di login SSO
            return $this-\u003eredirect_to( $this-\u003eoptions['url'] . '/session/sso_login?' . $q );
        }
    }

    // Restituisce null se non vengono trovati parametri SSO nella richiesta
    return null;
}

Impostazione del percorso di ritorno su URL non Discourse

Discourse ti consente di effettuare l’accesso a un utente e reindirizzarlo a un URL non Discourse. Nota che affinché ciò funzioni, è necessario aggiungere il dominio all’impostazione del sito discourse connect allowed redirect domains. Per impostazione predefinita, questa impostazione è vuota, impedendo i reindirizzamenti a URL non Discourse. Puoi anche usare * come carattere jolly per consentire tutti i domini. Se lo abiliti, assicurati di utilizzare l’URL assoluto nel parametro return_path per qualsiasi URL non Discourse verso cui desideri indirizzare gli utenti.

21 Mi Piace

Sto usando questo metodo ma ogni volta devo accedere tramite sso.

Come possiamo renderlo trasparente, nel senso che se ho già effettuato l’accesso a Discourse, non ci sarà bisogno di andare alla pagina sso per accedere di nuovo?

1 Mi Piace

A meno che qualcosa non sia cambiato, è così che ci si aspetta che funzioni il link. Ad esempio, se hai effettuato l’accesso a Discourse e fai clic su un link sul sito del provider SSO che punta a https://forum.example.com/session/sso?return_path=/t/some-slug/23, dovresti essere reindirizzato in modo trasparente a /t/some-slug/23 senza dover visitare prima la pagina di accesso.

1 Mi Piace

Sono già all’ultimo aggiornamento di discourse e questo è il modo in cui funziona per me l’sso:

Come puoi vedere sono già loggato, ma quando inserisco un url come https://forum.example.com/session/sso?return_path=/t/some-slug/23, verrei reindirizzato nuovamente alla pagina di login sso.

Penso che quello che sta succedendo sia che quando visiti un percorso come https://forum.example.com/session/sso?return_path=/t/some-slug/23, Discourse ti reindirizza all’URL di discourse connect, indipendentemente dal fatto che tu sia o meno connesso a Discourse. Questo accade qui:

Il sito del provider SSO dovrebbe quindi gestire il caso degli utenti che sono già connessi al sito. Ecco come il plugin WP Discourse lo gestisce:

Quel codice (ciò che segue l’istruzione else) gestisce il caso degli utenti che sono già connessi a WordPress. Vengono reindirizzati all’URL fornito dal parametro di query return_path. Quindi, dal punto di vista dell’utente, vengono portati direttamente all’URL di ritorno, ma ciò che accade in realtà è che vengono reindirizzati al sito del provider SSO, quindi di nuovo a Discourse.

Penso che il problema sul tuo sito sia che il tuo codice SSO non gestisce il caso degli utenti che sono già connessi al sito.

Al momento non ho le cose impostate per testare questo. È possibile che stia leggendo il codice in modo errato. Prima di guardare il codice, pensavo che venisse eseguito un controllo sul lato Discourse per vedere se l’utente era già connesso a Discourse, ma non sembra essere così che funziona.

3 Mi Piace

Grazie mille per la tua spiegazione.

Sì, è una cosa che andremo a correggere nel nostro SSO.

Tuttavia

Penso che avere questo controllo dal lato Discourse avrebbe creato una migliore esperienza utente.

1 Mi Piace

Ho modificato l’OP per aggiungere dettagli su come funziona il processo e su come gestire il caso di utenti già autenticati sul sito del provider SSO. È una domanda che è sorta alcune volte.

Forse una versione meno dettagliata di questo argomento potrebbe essere integrata in Setup DiscourseConnect - Official Single-Sign-On for Discourse (sso) - #482. Il parametro di query return_path non è menzionato in quell’argomento.