Come creare un pulsante SSO: un tutorial per l'accesso a Flask

Pubblicato: 2022-03-11

Le applicazioni spesso necessitano di funzionalità di accesso in modo che gli utenti possano salvare i dati, creare i propri profili o forse solo per limitare l'accesso a risorse sensibili. In un'app moderna, gli utenti si aspettano di disporre di funzionalità standard relative all'accesso come la verifica dell'e-mail, la reimpostazione della password o l'autenticazione a più fattori. Queste funzionalità, sebbene necessarie, non sono facili da ottenere e di solito non sono l'attività principale dell'app.

Dal lato utente, potrebbero non voler seguire il lungo processo di registrazione poiché devono creare e ricordare ancora un'altra coppia e-mail e password. Senza un gestore di password adeguato, gli utenti tendono a riutilizzare la stessa password, il che è terribile in termini di sicurezza.

Il single sign-on (SSO), noto soprattutto agli utenti come login con i pulsanti dei social media , è stato inventato come soluzione a questo problema. Per gli utenti, non passare attraverso un altro doloroso processo di registrazione è stato facile. Per le aziende, rimuovere l'attrito per gli utenti è sempre una grande vittoria e, per gli sviluppatori, tutte le funzionalità relative all'accesso sono ora delegate al provider di identità (Facebook, Google, Twitter, ecc.), il che significa meno codice! La tua app si fida semplicemente del provider di identità per svolgere il proprio lavoro di verifica dell'identità dell'utente.

SSO è solitamente alimentato dal protocollo OpenId Connect (OIDC) o SAML. SAML viene utilizzato principalmente nelle applicazioni aziendali. OIDC è basato su OAuth2 e utilizzato da provider di identità social come Facebook, Google, ecc. In questo post, ci concentreremo sul protocollo OIDC/OAuth2.

In questo tutorial sull'accesso a Flask, scriveremo una guida passo passo per aggiungere un pulsante di accesso SSO in un'applicazione Flask con SimpleLogin e Facebook come provider di identità. Questo può essere fatto senza utilizzare alcuna libreria esterna, ma per semplificare le complessità di OAuth, utilizzeremo Requests-OAuthlib, una libreria per integrare i provider OAuth. Se sei interessato a implementare SSO da zero, dai un'occhiata a Implementa SSO Login - the raw way .

Alla fine di questo articolo, dovresti avere un'app Flask con le seguenti pagine:

  • Homepage con pulsanti di accesso
  • Pagina delle informazioni sull'utente in cui, dopo l'accesso, l'utente sarà in grado di visualizzare informazioni come nome, e-mail e avatar

Tutto il codice per questo tutorial può essere trovato sul repository flask-social-login-example.

Una demo è disponibile anche qui. Sentiti libero di remixare il codice su Glitch.

Passaggio 1: app Bootstrap Flask

Installa flask e Requests-OAuthlib . Puoi anche usare virtualenv o pipenv per isolare l'ambiente.

pip install flask request_oauthlib

Crea app.py e il percorso che mostra un pulsante di accesso nella home page:

 import flask app = flask.Flask(__name__) @app.route("/") def index(): return """ <a href="/login">Login</a> """ if __name__ == '__main__': app.run(debug=True)

Eseguiamo questa app e verifichiamo che tutto funzioni bene:

 python app.py

Dovresti vedere questa pagina quando apri http://localhost:5000. Il codice completo è su step1.py.

Accedi con SimpleLogin

Passaggio 2: credenziali del provider di identità

Attualmente ci sono centinaia (se non migliaia) di provider di identità, i più popolari sono Facebook, Google, GitHub e Instagram. Per questo post, SimpleLogin è stato scelto per la sua facilità di sviluppo. Tuttavia, lo stesso codice funzionerà con qualsiasi provider di identità OAuth2. (Disclaimer: mi capita di essere il co-fondatore di SimpleLogin, il che, ehm, potrebbe essere stato un fattore nella mia decisione di usarlo.)

Vai su SimpleLogin e crea un account se non ne hai già uno, quindi crea una nuova app nella scheda Sviluppatore.

Nella pagina dei dettagli dell'app, copia il tuo AppID e AppSecret e salvali nell'ambiente variabile. Nella terminologia OAuth, client significa in realtà un'app di terze parti, ovvero la tua app. Possiamo inserire questi valori direttamente nel codice, ma è buona norma salvare le credenziali nelle variabili di ambiente. Questo è anche il terzo fattore in The Twelve Factors.

Impostazioni OAuth2

 export CLIENT_ID={your AppID} export CLIENT_SECRET={your AppSecret}

In app.py , aggiungi queste righe in cima al file per ottenere client id client e client secret .

 import os CLIENT_ID = os.environ.get("CLIENT_ID") CLIENT_SECRET = os.environ.get("CLIENT_SECRET")

Aggiungi anche questi URL OAuth nella parte superiore di app.py che verranno utilizzati nel passaggio successivo. Possono anche essere copiati nella pagina degli endpoint OAuth.

 AUTHORIZATION_BASE_URL = "https://app.simplelogin.io/oauth2/authorize" TOKEN_URL = "https://app.simplelogin.io/oauth2/token" USERINFO_URL = "https://app.simplelogin.io/oauth2/userinfo"

Dato che non vogliamo preoccuparci di configurare SSL ora, diciamo a Requests-OAuthlib che va bene usare il semplice HTTP:

 # This allows us to use a plain HTTP callback os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"

Come al solito, il codice per questo passaggio è su step2.py.

Passaggio 3: reindirizzamento dell'accesso

Quando un utente fa clic sul pulsante di accesso:

  1. L'utente verrà reindirizzato alla pagina di autorizzazione del provider di accesso all'identità chiedendo se desidera condividere le proprie informazioni con la tua app.
  2. Dopo l'approvazione dell'utente, verranno quindi reindirizzati a una pagina della tua app insieme a un code nell'URL che la tua app utilizzerà per scambiare un access token che ti consentirà in seguito di ottenere informazioni sull'utente dal fornitore di servizi.

Abbiamo quindi bisogno di due percorsi: un percorso di login che reindirizza l'utente al provider di identità e un percorso di callback che riceve il code e lo scambia con access token . Il percorso di richiamata è anche responsabile della visualizzazione delle informazioni sull'utente.

 @app.route("/login") def login(): simplelogin = requests_oauthlib.OAuth2Session( CLIENT_ID, redirect_uri="http://localhost:5000/callback" ) authorization_url, _ = simplelogin.authorization_url(AUTHORIZATION_BASE_URL) return flask.redirect(authorization_url) @app.route("/callback") def callback(): simplelogin = requests_oauthlib.OAuth2Session(CLIENT_ID) simplelogin.fetch_token( TOKEN_URL, client_secret=CLIENT_SECRET, authorization_response=flask.request.url ) user_info = simplelogin.get(USERINFO_URL).json() return f""" User information: <br> Name: {user_info["name"]} <br> Email: {user_info["email"]} <br> Avatar <img src="{user_info.get('avatar_url')}"> <br> <a href="/">Home</a> """

Facendo clic sul pulsante di accesso dovrebbe passare attraverso il seguente flusso. Il codice completo può essere trovato su GitHub in step3.py.

Accedi con SimpleLogin per consentire alle informazioni dell'utente

Fai il login con facebook

La configurazione dell'accesso a Facebook, Google e Twitter è un po' complessa e richiede passaggi aggiuntivi come l'impostazione di SSL o la scelta degli ambiti giusti. Questi vanno oltre lo scopo di questo articolo.

A parte un'interfaccia utente sofisticata, la parte più difficile dell'integrazione di Facebook potrebbe essere trovare un modo per servire la tua app Web su HTTPS localmente poiché la nuova versione di Facebook SDK non consente HTTP semplice locale. Consiglio di utilizzare Ngrok, uno strumento gratuito per avere un URL HTTPS rapido.

Passaggio 1: crea un'app Facebook

Vai su https://developers.facebook.com e crea una nuova app:

Crea un nuovo ID app

Quindi scegli "Integra Facebook Login" nella schermata successiva:

Integra l'accesso a Facebook

Passaggio 2: credenziali OAuth di Facebook

Fai clic su "Impostazioni/Base" a sinistra e copia l' ID app e il segreto dell'app . In realtà sono OAuth client-id e client-secret .

Impostazioni di base

Aggiorna client-id e client-secret .

 export FB_CLIENT_ID={your facebook AppId} export FB_CLIENT_SECRET={your facebook AppSecret}

Aggiorna AUTHORIZATION_BASE_URL e TOKEN_URL:

 FB_AUTHORIZATION_BASE_URL = "https://www.facebook.com/dialog/oauth" FB_TOKEN_URL = "https://graph.facebook.com/oauth/access_token"

La homepage:

 @app.route("/") def index(): return """ <a href="/fb-login">Login with Facebook</a> """

Passaggio 3: endpoint di accesso e richiamata

Se l'app viene servita dietro ngrok utilizzando il comando ngrok http 5000 , è necessario impostare l'URL corrente sull'URL ngrok.

 # Your ngrok url, obtained after running "ngrok http 5000" URL = "https://abcdefgh.ngrok.io"

Assicurati di aggiungere l'URL al tuo accesso/impostazioni di Facebook, impostazione degli URI di reindirizzamento OAuth validi:

URI di reindirizzamento OAuth validi

Per poter accedere all'e-mail di un utente, è necessario aggiungere email scope :

 FB_SCOPE = ["email"] @app.route("/fb-login") def login(): facebook = requests_oauthlib.OAuth2Session( FB_CLIENT_ID, redirect_uri=URL + "/fb-callback", scope=FB_SCOPE ) authorization_url, _ = facebook.authorization_url(FB_AUTHORIZATION_BASE_URL) return flask.redirect(authorization_url)

Il percorso di callback è un po' più complesso poiché Facebook richiede una correzione per la conformità:

 from requests_oauthlib.compliance_fixes import facebook_compliance_fix @app.route("/fb-callback") def callback(): facebook = requests_oauthlib.OAuth2Session( FB_CLIENT_ID, scope=FB_SCOPE, redirect_uri=URL + "/fb-callback" ) # we need to apply a fix for Facebook here facebook = facebook_compliance_fix(facebook) facebook.fetch_token( FB_TOKEN_URL, client_secret=FB_CLIENT_SECRET, authorization_response=flask.request.url, ) # Fetch a protected resource, ie user profile, via Graph API facebook_user_data = facebook.get( "https://graph.facebook.com/me?fields=id,name,email,picture{url}" ).json() email = facebook_user_data["email"] name = facebook_user_data["name"] picture_url = facebook_user_data.get("picture", {}).get("data", {}).get("url") return f""" User information: <br> Name: {name} <br> Email: {email} <br> Avatar <img src="{picture_url}"> <br> <a href="/">Home</a> """

Ora, quando fai clic su Accedi con Facebook, dovresti essere in grado di seguire l'intero flusso.

Accedi con il processo di Facebook

Il codice completo è su facebook.py.

Conclusione

Congratulazioni: hai integrato con successo l'accesso SSO in un'app Flask!

Per semplicità, questo tutorial non menziona altri concetti OAuth come ambito e stato, che sono importanti per difendersi dagli attacchi di falsificazione di richieste tra siti. Probabilmente dovresti anche memorizzare le informazioni sull'utente in un database che non è trattato in questo articolo.

L'app deve anche essere servita su https in produzione, cosa che può essere eseguita abbastanza facilmente oggi con Let's Encrypt.

Buona OAuthing!