Pular para o conteúdo principal

Como hospedar arquivos estáticos em um CDN com o Casdoor: S3, MinIO, Azure Blob e outros provedores de armazenamento

· Leitura de 11 min
Yang Luo
Casdoor Maintainer

Para hospedar arquivos estáticos em um CDN, coloque-os no armazenamento de objetos (Amazon S3, MinIO, Azure Blob Storage, Google Cloud Storage, Alibaba Cloud OSS ou Tencent Cloud COS), faça o CDN buscar desse bucket como sua origem e distribua URLs no domínio do CDN. No Casdoor, isso é uma única configuração: crie um provedor de armazenamento para o bucket e coloque o endereço do CDN no campo Domain. O Casdoor envia avatares e outros arquivos por meio da API do provedor e salva URLs que começam com esse domínio. O frontend do próprio Casdoor também pode vir de um CDN, por meio de frontendCdnUrl e staticBaseUrl em app.conf.

Provedores de armazenamento em resumo​

Um provedor de armazenamento decide onde o Casdoor grava os arquivos enviados: avatares de usuários, imagens de documentos de identidade, páginas de termos de uso e qualquer coisa enviada na página Resources. Você adiciona o provedor a uma aplicação, e os envios feitos nessa aplicação vão para ele. A visão geral dos provedores de armazenamento lista todos os tipos. Esta tabela cobre aqueles sobre os quais as pessoas geralmente perguntam:

ArmazenamentoTipo de provedor do CasdoorO Casdoor usa a API S3?Auto-hospedávelComo a URL pública é definida
Sistema de arquivos localLocal File SystemNão, arquivos simples em discoSim, é o servidor do CasdoorServido pelo Casdoor sob /files/. Domain é somente leitura
Amazon S3AWS S3SimNãoDomain: a URL do bucket ou um domínio CloudFront. Endpoint (Intranet): um endpoint VPC
MinIOMinIOSim, com requisições path-styleSimDomain: a URL do MinIO seguida pelo nome do bucket, ou um domínio de CDN
Alibaba Cloud OSSAliyun OSSNão, o SDK OSSNãoDomain: um domínio de CDN. Se estiver vazio, torna-se bucket.endpoint. Endpoint (Intranet): o endpoint interno
Tencent Cloud COSTencent Cloud COSNão, a API COSNãoDomain: um domínio de CDN
Azure Blob StorageAzure BlobNão, a API BlobNãoDomain: um domínio personalizado ou Front Door. O Casdoor adiciona o nome do contêiner ao caminho
Google Cloud StorageGoogle Cloud StorageNão, o cliente Go do GoogleNãoDomain: se estiver vazio, torna-se https://storage.googleapis.com. O Casdoor adiciona o nome do bucket ao caminho
Synology NASSynologyNão, a API DSM File StationSimSem campo Domain. A URL é baseada no Endpoint

O Casdoor também suporta Qiniu Cloud Kodo, CUCloud OSS e Casdoor, que armazena arquivos em outra instância do Casdoor. Os guias por provedor para Amazon S3, MinIO, Azure Blob, Google Cloud Storage, Alibaba Cloud OSS, Tencent Cloud COS, Synology NAS e o sistema de arquivos local mostram qual valor vai em qual campo.

Endpoint vs. Domain​

Esses dois campos têm funções diferentes, e a maioria dos problemas de CDN vem de confundi-los.

  • Endpoint é o endereço que o Casdoor usa para falar com a API de armazenamento: upload, exclusão, listagem. O CDN não está envolvido.
  • Endpoint (Intranet) substitui Endpoint quando isCloudIntranet = true está definido em app.conf. Isso mantém o tráfego de upload na rede interna do provedor quando o Casdoor executa na mesma nuvem. O campo aparece para AWS S3, Aliyun OSS, Azure Blob e CUCloud OSS.
  • Domain é a base da URL que o Casdoor salva e que os navegadores solicitam. Se você tiver um CDN, seu domínio vai aqui.
  • Path prefix é colocado antes de cada chave de objeto. Com um prefixo casdoor, um avatar termina sob casdoor/avatar/....

O Casdoor constrói a URL do arquivo a partir do esquema e host do Domain, depois o caminho do Domain, depois o path prefix, depois o caminho do arquivo. Um Domain sem esquema recebe https://. A parte do caminho do Domain também se torna parte da chave do objeto, então https://cdn.example.com/casdoor/ armazena arquivos sob casdoor/ no bucket. Para Azure Blob e Google Cloud Storage, o Casdoor adiciona o nome do contêiner ou bucket como o primeiro segmento de caminho após o host. Seu CDN precisa servir esse caminho.

Se Domain estiver vazio, o Casdoor preenche-o a partir do endpoint do provedor na primeira vez que usa o provedor e o salva. Às vezes, o resultado funciona, como com OSS e GCS. Às vezes não: para um endpoint S3 sem o nome do bucket, ou para MinIO, onde requisições estilo-path colocam o nome do bucket no caminho, a URL gerada perde o bucket. Defina Domain você mesmo, faça upload de um avatar de teste e abra a URL que o Casdoor retorna antes que qualquer outra pessoa use.

O provedor que o Casdoor usa para avatars copiados de logins sociais vem de defaultStorageProvider em app.conf. É o nome de um provedor pertencente ao admin (veja a referência de configuração):

defaultStorageProvider = provider_storage_s3
isCloudIntranet = false

Buckets públicos, buckets privados e URLs assinadas​

O Casdoor salva uma URL plana e permanente no campo avatar do usuário e no registro de recurso. Ele não cria URLs assinadas ou expiráveis para esses arquivos. Portanto, o que quer que esteja em Domain deve responder a um GET anônimo. Há duas maneiras de fazer isso.

Torne os objetos públicos. Com AWS S3 e MinIO, o Casdoor faz upload de cada objeto com a ACL canned public-read. Com Aliyun OSS, a biblioteca cliente faz o mesmo por padrão. No S3, isso conflita com os padrões para novos buckets: de acordo com a AWS, novos buckets usam a configuração Bucket owner enforced, que desabilita ACLs, e um upload que define uma ACL como public-read falha com AccessControlListNotSupported. É por isso que o guia Amazon S3 pede que você habilite ACLs e desative Block all public access. No OSS, uma ACL de objeto tem precedência sobre a ACL do bucket, então um objeto public-read pode ser lido mesmo em um bucket privado. O MinIO não usa a ACL para leituras anônimas. Ele usa uma política de bucket:

mc anonymous set download myminio/casdoor

Azure precisa permitir acesso anônimo na conta de armazenamento e o contêiner definido no nível de acesso Blob. Google Cloud Storage precisa da função Storage Object Viewer (roles/storage.objectViewer) concedida a allUsers no bucket.

Mantenha o bucket privado e deixe apenas o CDN lê-lo. O CDN assina suas requisições à origem, e os espectadores passam pelo CDN sem assinatura. Cada fornecedor tem sua própria versão:

  • CloudFront tem controle de acesso à origem (OAC). A AWS exige Bucket owner enforced para OAC, ou Bucket owner preferred se você precisar de ACLs.
  • Alibaba Cloud CDN pode buscar de um bucket OSS privado após você autorizá-lo.
  • Tencent Cloud CDN tem autenticação de pull de origem para buckets COS privados.
  • Azure Front Door Premium pode alcançar uma conta de armazenamento via Private Link.
  • O guia do Cloud CDN do Google também cobre acesso a buckets privados, onde a função Storage Object Viewer é atribuída a uma conta de serviço em vez de allUsers.

Isso oculta a URL própria do bucket, mas os arquivos ainda são públicos através do CDN. Com os tipos AWS S3 e Aliyun OSS, os objetos também permanecem legíveis em suas URLs de bucket, devido à ACL public-read que o Casdoor define.

Se os avatares não devem ser públicos de forma alguma, um CDN na frente do armazenamento de objetos é a ferramenta errada. Mantenha esses arquivos em um tipo de armazenamento que você controla e limite quem pode acessar esse host.

Cabeçalhos de cache e a armadilha do avatar​

No S3 e MinIO, o Casdoor define Content-Type a partir da extensão do arquivo quando faz upload. Ele não define Cache-Control em nenhum provedor. Isso significa que o TTL padrão do CDN se aplica. No CloudFront, objetos sem Cache-Control são armazenados em cache pelo TTL padrão, que é de 24 horas quando você não usa uma política de cache. Para controlar isso por objeto, adicione metadados Cache-Control no bucket. Para todo um caminho, use uma regra de cache no CDN.

Avatars need a short TTL. When a user changes their picture, Casdoor writes the new file to the same key, avatar/<organization>/<username>.<extension>, and saves the same URL. A long TTL means people see the old picture until it expires or until you purge or invalidate that path. Other uploads get a numbered suffix (-1, -2, ...) when the name is already taken, so a new upload gets a new URL and can be cached for a long time.

Um layout que funciona:

CaminhoCache sugerido
avatar/*TTL curto (minutos), ou purge ao mudar
resource/* e outros uploadsTTL longo
Assets frontend com hash (assets/*)TTL muito longo. O nome do arquivo muda a cada build

O próprio frontend do Casdoor em um CDN​

Separadamente dos uploads de usuários, há três maneiras de mover os arquivos estáticos próprios do Casdoor para fora do servidor Casdoor.

frontendCdnUrl. Use isto se você instalar o frontend do pacote npm casdoor-web. Aponte-o para um CDN npm, por exemplo:

frontendCdnUrl = "https://cdn.jsdelivr.net/npm/{name}@{version}"

O Casdoor lê o nome e a versão do pacote do package.json na pasta de build. Ele reescreve os links de script e folha de estilo em index.html para esse CDN e mantém os caminhos locais como fallback. Se um arquivo falhar ao carregar, o navegador o carrega do Casdoor, e um cookie mantém esse navegador nos arquivos locais pelo resto da sessão. Um frontend que você compila você mesmo não tem tal package.json, então a configuração não tem efeito nele.

O script de implantação. Para um frontend que você compila a partir do código-fonte, Hospedar os arquivos do frontend em um CDN explica deployment/deploy_test.go. Ele faz upload de web/build/assets/ por meio de um dos seus provedores de armazenamento e aponta o index.html para o Domain do provedor, que deve terminar com /. O Vite gera hashes nesses nomes de arquivo, portanto eles são adequados para o TTL longo na tabela acima.

staticBaseUrl. Isso define a origem das imagens padrão, como logotipos, ícones de provedores e o avatar padrão. O valor padrão é https://cdn.casbin.org, que serve o repositório casbin/static. Em uma rede sem acesso à internet, hospede uma cópia desse repositório você mesmo e aponte o staticBaseUrl para ela, conforme descrito em Hospedar arquivos estáticos em uma intranet.

Escolhendo uma opção​

  • Um servidor, base de usuários pequena: Local File System. Monte o diretório files em um volume se o Casdoor estiver sendo executado em um contêiner. O Casdoor envia X-Content-Type-Options: nosniff e uma Content-Security-Policy de sandboxing com esses arquivos, para que um arquivo HTML ou SVG enviado não possa executar scripts no seu domínio do Casdoor.
  • Auto-hospedado e compatível com S3: MinIO. É também o tipo sugerido pela documentação para outras lojas compatíveis com S3.
  • Já está em uma nuvem: use o armazenamento de objetos e o CDN dessa nuvem, defina Endpoint (Intranet) onde o Casdoor está sendo executado na mesma nuvem e defina o Domain para o CDN.

Referências​