我正在开发一个Django站点,该站点允许通过云服务连接到受限网络中的设备。设备通过VPN或SSH隧道连接到云服务器,客户端通过HTTP连接到虚拟主机。 Django部分是管理复杂的组织 - 角色 - 访问 - 用户关系所必需的。
目前我正在自定义Django中间件模块中进行访问控制,该模块解析HTTP_HOST,进行身份验证,获取页面并将其转发给原始请求者。问题是,当请求正在进行时,Django不会处理任何其他请求。 Celery没有解决问题,因为这不是一个真正的后台任务。客户端通过单个地址和端口提供服务,使防火墙规则不适合此任务。
相关代码如下:
class NodeProxyMiddleware:
def process_request(self, request, *args, **kwargs):
if not 'HTTP_HOST' in request.META:
return None
hardware_id = match_hwid.match(request.META["HTTP_HOST"])
if not hardware_id:
return None
kwargs["hardware_id"] = hardware_id.group("hwid")
if not authenticate(request, *args, **kwargs):
return HttpResponseForbidden("No access")
return proxy_request(request, *args, **kwargs)
@csrf_exempt
def proxy_request(request, *args, **kwargs):
# Get the port of target Node
hardware_id = kwargs.get("hardware_id", "")
try:
port = Node.objects.filter(hardware_id=hardware_id)[0].port
except IndexError: # Node with given hwid was not found
raise Http404
# We have to convert request.META back to original form manually
headers = convert_headers(request) # HTTP_FOO_BAR to Foo-Bar
headers["connection"] = "close"
connection = httplib2.Http(timeout=5)
url = "http://127.0.0.1:%d%s" % (port, request.META['PATH_INFO'])
method = request.method
# GET -- url ?d=a&t=a has to be urlencoded
if method == "GET":
data = None
if request.GET:
url += "?" + request.GET.urlencode()
# POST -- body has to be urlencoded
elif method == "POST":
data = request.POST.urlencode()
headers["content-type"] = "application/x-www-form-urlencoded"
try:
response, content = connection.request(
url, method, data, headers=headers)
except Exception as e:
print e
return HttpResponse(content=e, status=503)
django_response = HttpResponse(
content=content,
status=int(response["status"]),
mimetype=response["content-type"],
)
# Strip hop-by-hop headers -- See RFC2616 semantically transparent
# proxying. Also, WSGI forbids passing such headers back to it.
hop_by_hop_headers = [
"connection",
"keep-alive",
"proxy-authenticate",
"proxy-authorization",
"te",
"trailers",
"transfer-encoding",
"upgrade",
]
for key, value in response.iteritems():
if key.lower() in hop_by_hop_headers:
continue
django_response[key] = value
return django_response
通过调整上面的代码或其他设置,可以在Django中完成这种代理吗?我正在运行的软件堆栈是Nginx + uWSGI + Django 1.6。 uWSGI配置为:
[uwsgi]
chdir = /home/foo/production/
file = /home/foo/production/wsgi.py
home = /home/foo/virtualenv
master = true
processes = 8
socket = /var/nginx/foo.socket
chmod-socket = 666
vacuum = true
daemonize = /home/foo/production/uwsgi.log