2011-08-16 1 views
7

Je recréer un service dans Python/Flask et je rencontre un problème avec la façon dont les clients existants s'authentifient. Je dois faire correspondre le schéma des clients existants pour des raisons de compatibilité.Forcer Content-Type ou exposer request.data dans Flask pour un type de contenu connu

Les clients existants prennent le nom d'utilisateur, mot de passe et base64 l'encoder. Ce n'est pas l'authentification de base HTTP, malgré son semblable. Voici un exemple de code qui créerait cette demande de connexion.

credentials = { 
      'username': '[email protected]', 
      'password': 'password' 
} 
data = b64encode(urlencode(credentials)) 
request = urllib2.Request(loginURL) 
request.add_data(data) 
# request.add_header('Content-Type', 'application/gooblygop') 
# 'application/x-www-form-urlencoded' seems to be a default Content-Type 
login = urllib2.urlopen(request) 

Du côté du serveur, je prends les données POST et base64 décodent pour obtenir le nom d'utilisateur et mot de passe.

flask server: 
@app.route('/login', methods=['POST']) 
def login(): 
    error = None 
    if request.method == 'POST': 
     # post data: cGFzc3dvcmQ9ZGVmYXVsdCZlbWFpbD10ZXN0JTQwZXhhbXBsZS5jb20= 
     data = b64decode(request.data) 
     # decoded data: password=default&email=test%40example.com 
     return('ok') 

Le problème est le type de contenu. Si je spécifie un type de contenu inconnu dans le client (application/gooblygop), Flask expose les données POST à ​​request.data et je peux décoder la chaîne base64. Si je laisse le Content-Type par défaut (application/x-www-form-urlencoded), les données brutes ne sont pas exposées à request.data et je ne sais pas comment récupérer la chaîne encodée en base64 et en faire usage.

Le logiciel client existant est à peu près par défaut x-www-form-urlencoded, mais je ne peux pas m'attendre à ce que cela soit toujours le cas. Fondamentalement, j'ai besoin d'une méthode fiable côté serveur pour accéder à cette chaîne codée quel que soit le type de contenu indiqué par le programme client.

Autres notes: Je suis très nouveau sur Python, venant d'un arrière-plan PHP. Je suis donc très ouvert aux suggestions. En outre, ce projet est principalement pour un usage personnel.

Répondre

2

Vous voulez regarder l'objet request.form lorsque vous traitez des poteaux avec des types MIME normaux. Dans ce cas, vous avez une forme inhabituelle, mais voici une façon de le faire:

# mkreq.py 
from urllib import urlencode 
import urllib2 
from base64 import b64encode 

credentials = { 
      'username': '[email protected]', 
      'password': 'password' 
} 
data = b64encode(urlencode(credentials)) 
request = urllib2.Request("http://localhost:5000/login") 
request.add_data(data) 
request.add_header('Content-Type', 'application/gooblygop') 
# 'application/x-www-form-urlencoded' seems to be a default Content-Type 
login1 = urllib2.urlopen(request).read() 
print(login1) 
request2 = urllib2.Request("http://localhost:5000/login") 
request2.add_data(data) 
login2 = urllib2.urlopen(request2).read() 
print(login2) 

Vous voulez probablement modifier le bit de connexion pour vérifier le type MIME, voici une version avec un minimum de changements à votre configuration actuelle:

@app.route('/login', methods=['POST']) 
def login(): 
    error = None 
    if request.method == 'POST': 
     # post data: cGFzc3dvcmQ9ZGVmYXVsdCZlbWFpbD10ZXN0JTQwZXhhbXBsZS5jb20= 
     data = b64decode(request.data) 
     # decoded data: password=default&email=test%40example.com 
     if not data: 
      data = b64decode(request.form.keys()[0]) 
     special_mimetype = request.mimetype 
     return(special_mimetype + '\n' + data) 

C'est la sortie du premier exemple de code, avec deux demandes:

bvm$ python mkreq.py 
application/gooblygop 
username=test%40example.com&password=password 
application/x-www-form-urlencoded 
username=test%40example.com&password=password 
1

Avez-vous pensé à utiliser JSON pour passer vos données dans le POST? Flask a pris en charge le transfert de données json. En outre, si vous définissez le type de contenu dans les en-têtes à l'application/JSON flacon puis automatiquement dejson les données POST pour vous et le mettre dans request.json

Voici l'application demandant

import urllib2 
import json 

if __name__ == "__main__": 
    headers = {'Content-Type':'application/json'} 
    post_data = {"user":"test_user"} 
    print "Posting request" 
    req = urllib2.Request("http://localhost:5000/login", json.dumps(post_data), headers) 
    resp = urllib2.urlopen(req) 
    print "Response was %s" % resp.read() 

Voici la vue Flask

from flask import request 

@app.route('/login', methods=['POST']) 
def login(): 

    user = request.json['user'] 
    return user 

Je vous suggère de tester en utilisant boucle aussi bien si vous utilisez le terminal linux. Voici un exemple

curl -X POST -H "Content-Type:application/json" -s -d '{"user":"This is the username"}' 'localhost:5000/login' 

This is the username 
Questions connexes