Questo articolo ha il solo scopo didattico di illustrare il meccanismo di autenticazione basato su token e il codice qui contenuto non è adeguato per un ambiente di produzione senza opportune modifiche e migliorie. Inoltre, se si vuole implementare un meccanismo di autenticazione con token, si consiglia l’introduzione nel proprio progetto Flask di PyJWT, una libreria che implementa le specifiche RFC 7519.
Autenticazione Flask basata su token
Anzitutto vediamo il codice nella sua interezza per poi procedere nei punti successivi a commentarlo pezzo per pezzo
from flask import Flask, request, jsonify
import uuid
app = Flask(__name__)
# Dummy authentication credentials
USERNAME = 'admin' # Customize it
PASSWORD = 'password' # Customize it
# Dummy token dictionary to store authentication tokens
tokens = {}
# Route to get authentication token
@app.route('/api/v1/get-token', methods=['POST'])
def get_token():
auth = request.authorization
if auth and auth.username == USERNAME and auth.password == PASSWORD:
token = uuid.uuid4().hex
tokens[token] = {'username': auth.username}
return jsonify({'token': token}), 200
else:
return jsonify({'error': 'Unauthorized access'}), 401
# Token authentication decorator
def token_required(func):
def wrapper(*args, **kwargs):
token = request.headers.get('Authorization')
if token and token.split()[1] in tokens:
return func(*args, **kwargs)
else:
return jsonify({'error': 'Token is missing or invalid'}), 401
return wrapper
# Route to be protected with token authentication
@app.route('/api/your-endpoint', methods=['POST'])
@token_required
def your_endpoint():
pass
if __name__ == '__main__':
app.run(debug=True)
Considerazioni iniziali sulla sicurezza
Anzitutto è necessario ribadire che questo codice ha solo scopo didattico e non è adatto per la produzione. Il primo aspetto è relativo al fattore sicurezza. Ovviamente le costanti USERNAME e PASSWORD dovranno essere sostituite ed un sicuro sistema di autenticazione utente mediante username e password deve essere implementato.
Altra cosa da sostituire è il salvataggio del token e qui esistono molteplici aspetti che potrebbero essere discussi, ma che prescindono dallo scopo di questo articolo. Teniamo semplicemente a mente che salvare i token in un dizionario è una mossa non saggia e da evitare.
# Dummy authentication credentials
USERNAME = 'admin' # Customize it
PASSWORD = 'password' # Customize it
# Dummy token dictionary to store authentication tokens
tokens = {}
Rilascio del token
L’endpoint get-token è colui che dovrà essere invocato per ottenere il token di autenticazione. In questo esempio vengono verificate le credenziali USERNAME e PASSWORD, ma come abbiamo detto nelle considerazioni precedenti, la logica di controllo dell’autenticazione va implementata ex novo.
# Route to get authentication token
@app.route('/api/v1/get-token', methods=['POST'])
def get_token():
auth = request.authorization
if auth and auth.username == USERNAME and auth.password == PASSWORD:
token = uuid.uuid4().hex
tokens[token] = {'username': auth.username}
return jsonify({'token': token}), 200
else:
return jsonify({'error': 'Unauthorized access'}), 401
Decoratore ed endpoint da proteggere
Questo decoratore è colui che andremo ad applicare al nostro endpoint per proteggerlo mediante autenticazione basata su token
# Token authentication decorator
def token_required(func):
def wrapper(*args, **kwargs):
token = request.headers.get('Authorization')
if token and token.split()[1] in tokens:
return func(*args, **kwargs)
else:
return jsonify({'error': 'Token is missing or invalid'}), 401
return wrapper
Ed ecco qui il nostro endpoint protetto
# Route to be protected with token authentication
@app.route('/api/v1/your-endpoint', methods=['POST'])
@token_required
def your_endpoint():
pass