Controle de Acesso ao Servir Arquivos com Django/Python [Dica]
Publicado por Thiago Silva em 17/07/2020
[ Hits: 616 ]
Resolvi falar disso porque vi pela internet que isso é uma questão bem recorrente para quem desenvolve em Python com Django. A forma "normal" de servir arquivos seria declarando o MEDIA_ROOT no seu settings.py e adicionando a rota em urls.py, certo?
Bom, isso funciona, mas qualquer um pode acessar os arquivos lá. Digamos que sua pasta MEDIA fosse "uploads" e houvesse um arquivo com o nome "user_profile1_image.png", então QUALQUER UM que digitasse no navegador http://<seu domínio ou ip>/uploads/user_profile1_image.png veria a imagem. Quando se lida com arquivos sensíveis, isso não é nada bom.
Primeiramente, existem várias formas de se resolver essa questão. A maioria delas vai deixar o serviço por conta do Django. Mas além de aumentar o tamanho do código, pode também sobrecarregar o servidor, a depender. Em vez disso, você pode usar o seu próprio servidor para isso, de um jeito bem fácil, aliás. Aqui mostrarei como usar o Nginx para isso, mas é possível fazer algo parecido com o Apache também.
É bem simples. Siga até o arquivo de configuração do Nginx, em que o seu servidor foi configurado. Provavelmente...
nano /etc/nginx/sites-enabled/SEU_PROJETO
...deve te levar até lá. Você agora só precisa adicionar no bloco "server" o seguinte:
location /ARQUIVOS/ {
root /home/USER/PROJETO;
Onde ARQUIVOS é o nome da pasta a ser protegida e root /home/USER/PROJETO; é o caminho COMPLETO até a pasta raiz do seu projeto. Salve e feche.
Não é preciso fazer nada em settings.py, não adicione a pasta como MEDIA_ROOT e se você já fez isso, retire essa configuração.
Em urls.py crie uma rota para uma view como qualquer outra. Como exemplo,
path('file/', require_files),
Em views.py do app que vai consumir esses arquivos, crie a função:
def require_files(request):
response['X-Accel-Redirect'] = request.path
Perceba que alteramos o cabeçalho da resposta. É exatamente essa alteração que permite ao Nginx saber se deve ou não servir determinado arquivo. Nesse caso, apenas o pessoal da staff poderá acessá-los, mas com essa lógica você tem total liberdade para controlar a view que dará permissão de acesso como você bem quiser.
Por exemplo, se existe o model Pedido com um arquivo enviado pelo usuário e ele queira acessar, a sua view seria algo parecido com isso:
def require_files(request, id):
# Isso limitará a pesquisa ao usuário então se ele der um jeito de mandar o id de um pedido de outro usuário