我的理解是,在一个普通的React网站上,所有媒体都将从与前端文件(HTML、CSS和Javascript(相同的服务器上提供。
REST API后端将只提供存储这些图像的链接,并且它将由前端提供服务和显示。
问题是,如果这些图像是私人的,并且应该只有一个用户能够看到它们。如果有人掌握了图像的URL并打开它,他们就可以看到图像。
现代网站如何解决这个问题?Django和React之间的工作流程是什么,以确保用户的图像安全和隐私?
Step 1: All requests for media should go throught a specific view
Edit file myproject/urls.py and add:
from myproject.views import media_access
urlpatterns = [
...,
url(r'^media/(?P<path>.*)', media_access, name='media'),
]
Step 2: Add the view and check access
Add the following view in myproject/views.py:
from django.http import HttpResponse
from django.http import HttpResponseForbidden
def media_access(request, path):
"""
When trying to access :
myproject.com/media/uploads/passport.png
If access is authorized, the request will be redirected to
myproject.com/protected/media/uploads/passport.png
This special URL will be handle by nginx we the help of X-Accel
"""
access_granted = False
user = request.user
if user.is_authenticated():
if user.is_staff:
# If admin, everything is granted
access_granted = True
else:
# For simple user, only their documents can be accessed
user_documents = [
user.identity_document,
# add here more allowed documents
]
for doc in user_documents:
if path == doc.name:
access_granted = True
if access_granted:
response = HttpResponse()
# Content-type will be detected by nginx
del response['Content-Type']
response['X-Accel-Redirect'] = '/protected/media/' + path
return response
else:
return HttpResponseForbidden('Not authorized to access this media.')
Here the important part is about the variable user_documents. It should contain reference to all files the user has access. In my case I extended the User model to add a field identity_document that why I can access it here.
In this media_acces view, you can implement any authorization logic.
Step 3: Configure nginx
Here is a full example of nginx configuration. The important part is about location /protected/. We suppose that Django is available with Gunicorn on port 8080 for example.
upstream myprojectapp {
server localhost:8080;
}
server {
listen 80;
server_name myproject.com;
server_name_in_redirect on;
error_log /var/log/nginx/myproject-error.log crit;
access_log /var/log/nginx/myproject-access.log custom_combined;
root /path/to/my/django/project/static;
location ^~ /static/ {
alias /path/to/my/django/project/static/;
}
location /protected/ {
internal;
alias /path/to/my/django/project/;
}
location / {
include proxy_params;
proxy_pass http://myprojectapp;
proxy_buffering off;
}
}
You can notice there is no location ^~ /media/ that's because this URL is handle by django.
这更像是对其他人关于X-Accel
的回答的补充。X-Accel
解决了问题的前半部分,即为链路设置一个看门人。
问题的另一半是,有时你无法轻松地对用户进行身份验证,例如,在典型的React/DRF设置中,你将使用JWT,并且无法控制浏览器将向服务器发送哪些标头。您将有以下选项
-
您需要选择使用基于cookie的身份验证
-
在图像链接中实现自定义身份验证机制,类似于AWS S3预签名URL的工作方式。一个简单的方法是根据Nginx
secure_link
模块生成图像的URL。参考编号:https://www.nginx.com/blog/securing-urls-secure-link-module-nginx-plus/
我选择方法#2,通过拥有一个自定义字段/序列化程序类(即SecuredFilePathSerializer
(并使用它而不是FilePathField
。
实际上,在REST API端点提供图像的URL之前,可以使用Django REST框架授权框架对端点的请求和响应进行适当授权。
此外,您可以为您想要的最终目标编写自己的自定义Django中间件[HTTP挂钩]。
中间件可以根据您的需要自定义HTTP请求-响应行为。