Как сделать файл закрытым, защитив url-адрес, который могут видеть только аутентифицированные пользователи
мне было интересно, есть ли способ защитить изображение или файл, который будет скрыт, когда он не аутентифицирован.
предположим, что на моем веб-сайте есть изображение, которое можно увидеть, только если этот пользователь аутентифицирован. Но дело в том, что я могу скопировать URL или открыть изображение в новой вкладке.
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:
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)
3 ответов
защищая любой медиа-файл, чтобы не служить анонимным пользователем, лучший способ защиты 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}),
Примечание: ранее любой вошедший пользователь может получить доступ к любой странице, теперь это обновление ограничивает не пользователя для просмотра других файлов...
самый простой вариант-обслуживать файл из django, а затем добавить @login_required
оформителя к виду, вот так:
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
было бы лучше обрабатывать только аутентификацию, и пусть ваш веб-сервер обрабатывает обслуживание файлов. Вероятно, хорошо поместить их в другой каталог, чем ваш 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
за идею, как санировать имена файлов и т. д.