Flask
Autorizzazione e autenticazione
Ricerca…
Usando l'estensione login-flask
Uno dei modi più semplici per implementare un sistema di autorizzazione consiste nell'utilizzare l'estensione login-flask . Il sito web del progetto contiene un quickstart dettagliato e ben scritto, di cui una versione più breve è disponibile in questo esempio.
Idea generale
L'estensione espone un insieme di funzioni utilizzate per:
- registrazione utenti in
- disconnettendo gli utenti
- verificare se un utente è connesso o meno e scoprire quale utente è quello
Cosa non fa e cosa devi fare da solo:
- non fornisce un modo di memorizzare gli utenti, ad esempio nel database
- non fornisce un modo per controllare le credenziali dell'utente, ad esempio nome utente e password
Di seguito c'è una serie minima di passaggi necessari per far funzionare tutto.
Raccomanderei di inserire tutto il codice relativo auth.py
in un modulo o pacchetto separato, ad esempio auth.py
In questo modo è possibile creare separatamente classi, oggetti o funzioni personalizzate.
Creare un LoginManager
L'estensione utilizza una classe LoginManager
che deve essere registrata sull'oggetto dell'applicazione Flask
.
from flask_login import LoginManager
login_manager = LoginManager()
login_manager.init_app(app) # app is a Flask object
Come accennato in precedenza, LoginManager
può essere ad esempio una variabile globale in un file o pacchetto separato. Quindi può essere importato nel file in cui è stato creato l'oggetto Flask
o nella funzione di fabbrica dell'applicazione e inizializzato.
Specifica una richiamata utilizzata per il caricamento degli utenti
Un utente verrà normalmente caricato da un database. Il callback deve restituire un oggetto che rappresenta un utente corrispondente all'ID fornito. Dovrebbe restituire None
se l'ID non è valido.
@login_manager.user_loader
def load_user(user_id):
return User.get(user_id) # Fetch the user from the database
Questo può essere fatto direttamente sotto la creazione del tuo LoginManager
.
Una classe che rappresenta il tuo utente
Come accennato, il callback user_loader
deve restituire un oggetto che rappresenta un utente. Cosa significa esattamente? Ad esempio, tale oggetto può essere un wrapper attorno agli oggetti utente memorizzati nel database o semplicemente direttamente un modello dal database. Questo oggetto deve implementare i seguenti metodi e proprietà. Ciò significa che se il callback restituisce il modello del database, è necessario assicurarsi che le proprietà e i metodi citati vengano aggiunti al modello.
is_authenticated
Questa proprietà dovrebbe restituire
True
se l'utente è autenticato, cioè hanno fornito credenziali valide. Dovrai assicurarti che gli oggetti che rappresentano i tuoi utenti restituiti dal callbackuser_loader
restituiscanoTrue
per quel metodo.is_active
Questa proprietà dovrebbe restituire True se questo è un utente attivo - oltre ad essere autenticato, hanno anche attivato il loro account, non sono stati sospesi, o qualsiasi condizione che l'applicazione ha per il rifiuto di un account. Gli account inattivi potrebbero non accedere. Se non si dispone di un meccanismo presente, restituire
True
da questo metodo.is_anonymous
Questa proprietà dovrebbe restituire True se si tratta di un utente anonimo. Ciò significa che l'oggetto utente restituito dalla callback
user_loader
deve restituireTrue
.get_id()
Questo metodo deve restituire un Unicode che identifica in modo univoco questo utente e può essere utilizzato per caricare l'utente dal callback
user_loader
. Nota che questo deve essere un unicode: se l'ID è nativamente un int o qualche altro tipo, dovrai convertirlo in unicode. Se il callbackuser_loader
restituisce oggetti dal database, questo metodo restituirà molto probabilmente l'ID del database di questo particolare utente. Lo stesso ID dovrebbe ovviamente causare il callbackuser_loader
per restituire lo stesso utente in un secondo momento.
Se si desidera semplificare le cose da soli (** è in realtà consigliato) è possibile ereditare da UserMixin
l'oggetto restituito dal callback user_loader
(presumibilmente un modello di database). Puoi vedere come questi metodi e proprietà sono implementati di default in questo mixin qui .
Registrazione degli utenti in
L'estensione lascia la convalida del nome utente e della password immessi dall'utente all'utente. In effetti l'estensione non interessa se si utilizza una combinazione di nome utente e password o altro meccanismo. Questo è un esempio per la registrazione degli utenti nell'uso di username e password.
@app.route('/login', methods=['GET', 'POST'])
def login():
# Here we use a class of some kind to represent and validate our
# client-side form data. For example, WTForms is a library that will
# handle this for us, and we use a custom LoginForm to validate.
form = LoginForm()
if form.validate_on_submit():
# Login and validate the user.
# user should be an instance of your `User` class
login_user(user)
flask.flash('Logged in successfully.')
next = flask.request.args.get('next')
# is_safe_url should check if the url is safe for redirects.
# See http://flask.pocoo.org/snippets/62/ for an example.
if not is_safe_url(next):
return flask.abort(400)
return flask.redirect(next or flask.url_for('index'))
return flask.render_template('login.html', form=form)
In generale, gli utenti di logging si ottengono chiamando login_user e passando un'istanza di un oggetto che rappresenta l'utente menzionato in precedenza. Come mostrato, ciò accade di solito dopo aver recuperato l'utente dal database e aver convalidato le sue credenziali, tuttavia l'oggetto utente appare magicamente in questo esempio.
Ho effettuato l'accesso a un utente, e ora?
L'oggetto restituito dal callback user_loader
è accessibile in più modi.
Nei modelli:
L'estensione la inietta automaticamente sotto il nome
current_user
usando un processore di contesto del modello. Per disabilitare tale comportamento e utilizzare il set di processori personalizzatoadd_context_processor=False
nel costruttore diLoginManager
.{% if current_user.is_authenticated %} Hi {{ current_user.name }}! {% endif %}
Nel codice Python:
L'estensione fornisce un oggetto associato alla richiesta denominato
current_user
.from flask_login import current_user @app.route("/hello") def hello(): # Assuming that there is a name property on your user object # returned by the callback if current_user.is_authenticated: return 'Hello %s!' % current_user.name else: return 'You are not logged in!'
Limitare l'accesso rapidamente usando un decoratore Un decoratore
login_required
può essere utilizzato per limitare l'accesso rapidamente.from flask_login import login_required @app.route("/settings") @login_required def settings(): pass
Registrazione degli utenti
Gli utenti possono essere disconnessi chiamando logout_user()
. Sembra che sia sicuro farlo anche se l'utente non ha effettuato l'accesso in modo che il decoratore @login_required
possa molto probabilmente essere ommited.
@app.route("/logout")
@login_required
def logout():
logout_user()
return redirect(somewhere)
Cosa succede se un utente non ha effettuato l'accesso e current_user
all'oggetto current_user
?
Per difetto viene restituito un AnonymousUserMixin :
-
is_active
eis_authenticated
sonoFalse
-
is_anonymous
èTrue
-
get_id()
restituisceNone
Per utilizzare un oggetto diverso per gli utenti anonimi, è possibile chiamare un oggetto chiamabile (di classe o di fabbrica) che crea utenti anonimi su LoginManager
con:
login_manager.anonymous_user = MyAnonymousUser
Cosa succederà?
Questo conclude l'introduzione di base all'estensione. Per ulteriori informazioni sulla configurazione e sulle opzioni aggiuntive, si consiglia vivamente di leggere la guida ufficiale .
Timeout della sessione di accesso
È buona norma interrompere la sessione di accesso dopo un determinato periodo di tempo, è possibile farlo con Flask-Login.
from flask import Flask, session
from datetime import timedelta
from flask_login import LoginManager, login_require, login_user, logout_user
# Create Flask application
app = Flask(__name__)
# Define Flask-login configuration
login_mgr = LoginManager(app)
login_mgr.login_view = 'login'
login_mgr.refresh_view = 'relogin'
login_mgr.needs_refresh_message = (u"Session timedout, please re-login")
login_mgr.needs_refresh_message_category = "info"
@app.before_request
def before_request():
session.permanent = True
app.permanent_session_lifetime = timedelta(minutes=5)
La durata predefinita della sessione è di 31 giorni, l'utente deve specificare la vista di aggiornamento del login in caso di timeout.
app.permanent_session_lifetime = timedelta(minutes=5)
Sopra la linea costringerà l'utente a riconnettersi ogni 5 minuti.