简体   繁体   English

强制 Content-Type 或公开 Flask 中已知内容类型的 request.data

[英]Force Content-Type or expose request.data in Flask for known content-type

I am recreating a service in Python/Flask and am running into an issue with the way the existing clients authenticate.我正在 Python/Flask 中重新创建服务,并且遇到了现有客户端身份验证方式的问题。 I have to match the existing clients scheme for compatibility reasons.出于兼容性原因,我必须匹配现有的客户端方案。

The existing clients take the username, password and base64 encode it.现有客户端使用用户名、密码和 base64 对其进行编码。 This is not HTTP Basic Authentication, despite sounding similar.这不是 HTTP 基本身份验证,尽管听起来很相似。 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.在服务器端,我将 POST 数据和 base64 解码以再次获取用户名和密码信息。

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.如果我在客户端(应用程序/gooblygop)中指定未知的内容类型,Flask 会将 POST 数据暴露给 request.data,我可以解码 base64 字符串。 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.如果我将 Content-Type 保留为默认值(application/x-www-form-urlencoded),原始数据不会暴露给 request.data 并且我不知道如何检索 base64 编码字符串并使用它。

The existing client software all pretty much defaults to x-www-form-urlencoded, but I can't rely on that always being the case.现有的客户端软件几乎都默认为 x-www-form-urlencoded,但我不能总是这样。

Essentially, I need a reliable, server-side method for accessing that encoded string no matter what Content-Type the client program states.本质上,我需要一种可靠的服务器端方法来访问该编码字符串,无论客户端程序声明什么 Content-Type。

Other notes: I am very new to Python, coming from a PHP background.其他说明:我对 Python 非常陌生,来自 PHP 背景。 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.在处理具有正常 mimetype 的 urlencoded 帖子时,您想查看request.form object。 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:您可能想要修改登录位以检查 mimetype,这是一个对您当前设置进行最小更改的版本:

@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:这是第一个代码示例的 output,有两个请求:

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?您是否考虑过使用 json 在 POST 中传递您的数据? Flask has built in support for passing json data. Flask 内置支持传递 json 数据。 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另外,如果你将 headers 中的 Content-Type 设置为 application/json ,那么 flask 会自动为你解压 POST 数据并放入 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这是 Flask 视图

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.如果您使用的是 linux 终端,我建议您也使用 curl 进行测试。 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM