【问题标题】:How to to make a file private by securing the url that only authenticated users can see如何通过保护只有经过身份验证的用户才能看到的 url 来使文件私有
【发布时间】:2015-03-16 11:07:15
【问题描述】:

我想知道是否有一种方法可以保护未经身份验证时隐藏的图像或文件。

假设我的网站中有一张图片,只有在该用户经过身份验证后才能看到。但问题是我可以复制网址或在新选项卡中打开图像。

http://siteis.com/media/uploaded_files/1421499811_82_Chrysanthemum.jpg

同样,即使我没有通过身份验证,我也可以通过访问该 url 来查看该特定图像。所以,我的问题是,如何保护文件,以便只有经过身份验证的用户才能看到?

更新:

查看:

def pictures(request, user_id):
    user = User.objects.get(id=user_id)
    all = user.photo_set.all()
    return render(request, 'pictures.html',{
        'pictures': all
    })

型号:

def get_upload_file_name(instance, filename):
    return "uploaded_files/%s_%s" %(str(time()).replace('.','_'), filename)

class Photo(models.Model):
    photo_privacy = models.CharField(max_length=1,choices=PRIVACY, default='F')
    user = models.ForeignKey(User)
    image = models.ImageField(upload_to=get_upload_file_name)

设置:

if DEBUG:
    MEDIA_URL = '/media/'
    STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), "myproject", "static", "static-only")
    MEDIA_ROOT = os.path.join(os.path.dirname(BASE_DIR), "myproject", "static", "media")
    STATICFILES_DIRS = (
    os.path.join(os.path.dirname(BASE_DIR), "myproject", "static", "static"),
    )

更新:

模板:

{% if pictures %}
    {% for photo in pictures %}
        <img src="/media/{{ photo.image }}" width="300" alt="{{ photo.caption }}"/>
    {% endfor %}
{% else %}
    <p>You have no picture</p>
{% endif %}

网址:

url(r'^(?P<user_name>[\w@%.]+)/photos/$', 'pictures.views.photos', name='photos'),

if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

【问题讨论】:

  • 一种方法是让控制器处理 URL /media/uploaded_files/* 并检查凭据。如果未授权,则返回 404 状态。
  • @Javier 请你看一下更新,并建议我如何去做。谢谢。
  • 文件的 URL 现在应该是一个逻辑 URL,而不是静态的一部分。然后我会做一些类似于@Burhan Khalid 发布的事情。
  • @Javier 我怎样才能使它合乎逻辑?在 settings.py?你能回答它而不是评论。我对 Django 很陌生。如果可以的话,我将不胜感激。

标签: python django url authentication file-access


【解决方案1】:

通过保护任何媒体文件不被匿名用户提供,更好的方式 url 保护。

代码(更新):

from django.conf.urls import patterns, include, url
from django.contrib.auth.decorators import login_required
from django.views.static import serve
from django.conf import settings

from django.core.exceptions import ObjectDoesNotExist
from django.shortcuts import HttpResponse

@login_required
def protected_serve(request, path, document_root=None):
    try:
        obj = Photobox.objects.get(user=request.user.id)
        obj_image_url = obj.image.url
        correct_image_url = obj_image_url.replace("/media/", "")
        if correct_image_url == path:
            return serve(request, path, document_root)
    except ObjectDoesNotExist:
        return HttpResponse("Sorry you don't have permission to access this file")


url(r'^{}(?P<path>.*)$'.format(settings.MEDIA_URL[1:]), protected_serve, {'file_root': settings.MEDIA_ROOT}),

注意:以前任何登录用户都可以访问任何页面,现在此更新限制非用户查看其他文件...

【讨论】:

  • 你能告诉我如何在模板中显示照片吗?我会很感激的。谢谢。
  • 是的,我有工作代码。它确实向我显示了模板中的照片。问题是我可以复制图像的 url 并以匿名用户身份打开它。我尝试了您的代码,复制了您的视图和网址。但一切都没有改变。如果您能详细说明,将不胜感激。
  • 这适用于我的机器。但不是当我使用亚马逊 s3 时。你能更新一下答案吗?
  • @Robin 其实上面的方法有一个安全漏洞。 Any logged in user can access that file。所以我会先看看。
  • 谢谢!你真是太好了。
【解决方案2】:

最好只处理身份验证,让您的网络服务器处理文件服务。最好将它们放在与settings.MEDIA_ROOT 不同的目录中,以防止您的网络服务器在您处理请求之前提供文件,例如project_root/web-private/media/

import os

@login_required
def protected_file(request, path):
    # set PRIVATE_MEDIA_ROOT to the root folder of your private media files
    name = os.path.join(settings.PRIVATE_MEDIA_ROOT, path)
    if not os.path.isfile(name):
        raise Http404("File not found.")

    # set PRIVATE_MEDIA_USE_XSENDFILE in your deployment-specific settings file
    # should be false for development, true when your webserver supports xsendfile
    if settings.PRIVATE_MEDIA_USE_XSENDFILE:
        response = HttpResponse()
        response['X-Accel-Redirect'] = filename # Nginx
        response['X-Sendfile'] = filename # Apache 2 with mod-xsendfile
        del response['Content-Type'] # let webserver regenerate this
        return response
    else:
        # fallback method
        from django.views.static import serve
        return serve(request, path, settings.PRIVATE_MEDIA_ROOT)

由于您的网络服务器在提供静态文件方面比 Django 更好,这将加快您的网站速度。查看django.views.static.serve 了解如何清理文件名等。

【讨论】:

  • 要使用这种方法,我需要修改 Apache 2 的配置吗?
  • @RenelChesak 我主要将它与 Ngnix 一起使用。您可能必须在 Apache 上安装并启用 mod_xsendfile,但我不确定详细信息。
  • 这是一个非常有用的 Apache 设置教程:h3xed.com/web-development/…。 @knbk 对于您上面的代码,这需要在主项目的 urls.py 中,还是需要在应用程序的 views.py 中作为基于函数的视图?
  • 您上面的代码能否用于控制对另一个基于函数的视图中指定的文件的访问?另外,您建议在 urls.py 中添加什么?
【解决方案3】:

最简单的选择是从 django 提供文件,然后将 @login_required decorator 添加到视图中,如下所示:

import os
import mimetypes
from django.core.servers.basehttp import FileWrapper
from django.contrib.auth.decorators import login_required

@login_required
def sekret_view(request, path=None):
   filename = os.path.basename(path)
   response = HttpResponse(FileWrapper(open(path)),
                           content_type=mimetypes.guess_type(path)[0])
   response['Content-Length'] = os.path.getsize(path)
   return response

【讨论】:

  • 感谢您的回答。但是我对 django 很陌生,对于如何在模板中显示它并没有太多了解。如果你能请你看看更新并告诉我如何,我将非常感激。
猜你喜欢
  • 1970-01-01
  • 2017-01-17
  • 2018-09-09
  • 2019-01-25
  • 2019-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多