J'ai une petite API à laquelle j'aimerais ajouter une authentification. J'aimerais pouvoir générer des clés d'API pour les consommateurs d'API; les consommateurs peuvent alors utiliser notamment les clés avec leurs demandes de demandes.
Existe-t-il une bibliothèque Flask qui fait quelque chose comme ça? Ou y a-t-il une façon typique de le faire? J'ai fait une recherche et je suis vraiment tombé sur this , qui ne va pas vraiment en profondeur. Je cherche une bibliothèque s'il y en a une.
Pour les clés d'authentification, créez une valeur aléatoire et stockez cette valeur dans une base de données. random()
fournit une entropie insuffisante pour des choses comme celle-ci, utilisez donc os.urandom()
.
Le lien que vous avez publié contient un très bon exemple de la façon de gérer les choses avec une fonction de décorateur. Dans la fonction décorateur, vérifiez que la valeur appkey est définie dans la demande, vérifiez qu'elle est valide dans la base de données, puis renvoyez la fonction. Si la clé d'application n'est pas valide, raise AuthenticationError("Invalid appkey")
et vous avez terminé.
L'exemple auquel vous avez lié est un peu déroutant. J'aime la démonstration de Comment faire une chaîne de décorateurs de fonction? mieux.
def checkAppKey(fn):
def inner(*args, **kwargs): #appkey should be in kwargs
try:
AppKey.get(appkey)
except KeyError:
raise AuthenticationError("Invalid appkey")
#Whatever other errors can raise up such as db inaccessible
#We were able to access that API key, so pass onward.
#If you know nothing else will use the appkey after this, you can unset it.
return fn(*args, **kwargs)
return inner
Voici une fonction qui utilise hashlib qui a assez bien fonctionné pour moi:
def generate_hash_key():
"""
@return: A hashkey for use to authenticate agains the API.
"""
return base64.b64encode(hashlib.sha256(str(random.getrandbits(256))).digest(),
random.choice(['rA', 'aZ', 'gQ', 'hH', 'hG', 'aR', 'DD'])).rstrip('==')
Une solution possible pour implémenter cela dans l'application pourrait être d'appliquer un décorateur sur chaque itinéraire que vous souhaitez protéger.
Exemple:
def get_apiauth_object_by_key(key):
"""
Query the datastorage for an API key.
@param ip: ip address
@return: apiauth sqlachemy object.
"""
return model.APIAuth.query.filter_by(key=key).first()
def match_api_keys(key, ip):
"""
Match API keys and discard ip
@param key: API key from request
@param ip: remote Host IP to match the key.
@return: boolean
"""
if key is None or ip is None:
return False
api_key = get_apiauth_object_by_key(key)
if api_key is None:
return False
Elif api_key.ip == "0.0.0.0": # 0.0.0.0 means all IPs.
return True
Elif api_key.key == key and api_key.ip == ip:
return True
return False
def require_app_key(f):
"""
@param f: flask function
@return: decorator, return the wrapped function or abort json object.
"""
@wraps(f)
def decorated(*args, **kwargs):
if match_api_keys(request.args.get('key'), request.remote_addr):
return f(*args, **kwargs)
else:
with log_to_file:
log.warning("Unauthorized address trying to use API: " + request.remote_addr)
abort(401)
return decorated
Et puis vous pouvez utiliser le décorateur en tant que tel:
@require_app_key
def delete_cake(version, cake_id):
"""
Controller for API Function that gets a cake by ID
@param cake_id: cake id
@return: Response and HTTP code
"""
Cet exemple utilise SQLAlchemy pour stocker des clés dans la base de données (vous pouvez utiliser SQLite).
Vous pouvez voir l'implémentation ici: https://github.com/haukurk/flask-restapi-recipe .
La façon "typique" de générer une clé API est de créer un UUID (généralement en créant un hachage md5 d'un sous-ensemble d'informations utilisateur + des informations quelque peu aléatoires (comme l'heure actuelle)).
Cependant, toutes les clés d'API doivent être des UUID. Le hachage hexadécimal créé par md5 répond à cette exigence, mais il existe certainement d'autres méthodes.
Une fois que vous avez créé une clé pour l'utilisateur, stockez-la dans la base de données dans le cadre des informations utilisateur et vérifiez que sa clé (généralement stockée dans un cookie) correspond à ce que vous avez. Les mécanismes réels de ceci sont (quelque peu) décrits dans la page à laquelle vous avez lié.