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

发布于 2024-11-29 19:51:33 字数 1485 浏览 1 评论 0原文

我正在 Python/Flask 中重新创建服务,但遇到了现有客户端身份验证方式的问题。出于兼容性原因,我必须匹配现有的客户端方案。

现有的客户端获取用户名、密码并对其进行 Base64 编码。尽管听起来很相似,但这不是 HTTP 基本身份验证。下面是一些创建此登录请求的示例代码。

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)

在服务器端,我获取 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')

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

现有的客户端软件几乎都默认为 x-www-form-urlencoded,但我不能相信情况总是如此。

本质上,我需要一种可靠的服务器端方法来访问该编码字符串,无论客户端程序声明什么内容类型。

其他说明: 我对 Python 非常陌生,有 PHP 背景。所以我非常愿意接受建议。此外,该项目主要供个人使用。

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

高跟鞋的旋律 2024-12-06 19:51:33

在处理具有普通 mime 类型的 urlencoded 帖子时,您需要查看 request.form 对象。在这种情况下,您有一个不寻常的表单,但这里有一个方法:

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

您可能想要修改登录位来检查 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)

这是第一个的输出代码示例,有两个请求:

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

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

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
柠北森屋 2024-12-06 19:51:33

您是否考虑过使用 json 在 POST 中传递数据? Flask 内置了对传递 json 数据的支持。另外,如果你将 headers 中的 Content-Type 设置为 application/json 那么 Flask 会自动为你 dejson POST 数据并将其放入 request.json

这是请求的应用程序

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

这是 Flask 视图

from flask import request

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

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

我建议你使用curl进行测试如果您使用的是 Linux 终端,也是如此。这是一个例子

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

This is the username

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文