Django Rest Framework和React前端:如何防止未经授权的用户在获得图像URL后查看私人图像



我的理解是,在一个普通的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,并且无法控制浏览器将向服务器发送哪些标头。您将有以下选项

  1. 您需要选择使用基于cookie的身份验证

  2. 在图像链接中实现自定义身份验证机制,类似于AWS S3预签名URL的工作方式。一个简单的方法是根据Nginxsecure_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请求-响应行为。

最新更新