Controle de Acesso ao Servir Arquivos com Django/Python

Publicado por Thiago Silva em 17/07/2020

[ Hits: 2.379 ]

 


Controle de Acesso ao Servir Arquivos com Django/Python



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.

Como resolver isso?

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.

Mão na massa!

É 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/ {
          internal;
          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,

urlpatterns = [
      ...,
      path('file/', require_files),
      ...
]

Em views.py do app que vai consumir esses arquivos, crie a função:

def require_files(request):
        if request.user.is_staff:
             response = HttpResponse(status=200)
             response['Content-Type'] = ""
             response['X-Accel-Redirect'] = request.path
             return response

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:

@login_required(login_url="/login/")
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
        # será negado
        pedido = Pedido.objects.filter(id=id,user_id=request.user.id)
        # Garante que o pedido existe
        if pedido:
             response = HttpResponse(status=200)
             response['Content-Type'] = ""
             response['X-Accel-Redirect'] = '/' + pedido[0].arquivo
             return response

É isso, pessoal, até mais!

Outras dicas deste autor

Executar Script na Inicialização do Sistema com Systemd

Dash to Dock no Gnome 3.34

Spotify no Arch Linux

Remover pedido de senha para Chaveiro de Sessão

Instalação do OpenOffice no Arch Linux

Leitura recomendada

Acessibilidade no VIM

Como usar o Wine

Diálogos traduzidos para FreedroidRPG

Compilar kernel no Debian? Mamão com açúcar!

Organização de arquivos na compilação de programas

  

Comentários

Nenhum comentário foi encontrado.



Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts