Type or expose request.data in Flask for known content

I am recreating a service in Python/Flask and am running into an issue with the way the existing clients authenticate. I have to match the existing clients scheme for compatibility reasons.

The existing clients take the username, password and base64 encode it. This is not HTTP Basic Authentication, despite sounding similar. Below is some sample code that would create this login request.

credentials = {
            'username': 'test@example.com',
            '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)

On the server side, I take the POST data and base64 decode it to get the username and password information again.

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')

The problem is the Content Type. If I specify an unknown Content-Type in the client (application/gooblygop), Flask exposes the POST data to request.data and I can decode the base64 string. If I leave the Content-Type as default (application/x-www-form-urlencoded), the raw data is not exposed to request.data and I don't know how to retrieve the base64 encoded string and make use of it.

The existing client software all pretty much defaults to x-www-form-urlencoded, but I can't rely on that always being the case.

Essentially, I need a reliable, server-side method for accessing that encoded string no matter what Content-Type the client program states.

Other notes: I am very new to Python, coming from a PHP background. So I am very open to suggestions. Also, this project is primarily for personal use.


You want to look at the request.form object when dealing with urlencoded posts with normal mimetypes. In this case you have an unusual form, but here is a way to do it:

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

credentials = {
            'username': 'test@example.com',
            '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)

You probably want to modify the login bit to check the mimetype, here is a version with minimal changes to your current setup:

@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)

This is the output of the first code sample, with two requests:

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

Have you thought about using json to pass your data in the POST? Flask has built in support for passing json data. In addition, if you set the Content-Type in the headers to application/json then flask will automatically dejson the POST data for you and put it in request.json

Here is the requesting application

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()  

This is the Flask view

from flask import request

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

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

I suggest you test using curl as well if you are using the linux terminal. Here is an example

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

This is the username
链接地址: http://www.djcxy.com/p/9024.html

上一篇: iOS相当于在Android中启动一个Activity

下一篇: 在Flask中键入或显示已知内容的request.data