Estou tentando escrever uma API REST simples e atualmente estou tentando configurar corretamente meu .htaccess
arquivo.
O que eu gostaria de alcançar é o seguinte:
- tem
RewriteRule
s para direcionar solicitações para o RestController real - capturar todas as solicitações não atendidas explicitamente com um
RewriteRule
antes com um erro FITTING- solicitações que visam qualquer arquivo, subdiretório ou arquivo no subdiretório não tratado com um anterior
RewriteRule
devem ser respondidas403
- solicitações que visam qualquer arquivo ou subdiretório inexistente devem ser respondidas
404
- solicitações que visam qualquer arquivo, subdiretório ou arquivo no subdiretório não tratado com um anterior
O que consegui até agora é:
- ✅ servindo arquivos inexistentes, subdiretórios e arquivos em subdiretórios
404
- ✅ servindo arquivos e subdiretórios existentes sem a devida
RewriteRule
403
- ❌ encaminhamento de solicitações de API válidas para o endpoint adequado (parou de funcionar depois que adicionei a última
403
regra) - ❌ servindo
403
para arquivos existentes EM SUBDIRS sem os devidosRewriteRule
- ex. quando tento acessardomain.com/subdir/existingfile.pdf
, na verdade mostra o arquivo, o que não quero.
Como os subdiretórios podem ser criados dinamicamente, desejo que TODOS os subdiretórios e arquivos neles sejam tratados 403 sem precisar especificá-los manualmente.
Esta é a minha corrente .htaccess
:
Options -Indexes
RewriteEngine on
RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
# REST mappings
RewriteRule ^json$ RestController.php?key=json [L,nc,qsa]
RewriteRule ^file/(.*)$ RestController.php?key=file&id=$1 [L,nc,qsa]
RewriteRule ^actions$ RestController.php?key=actions&id=none [L,nc,qsa]
RewriteRule ^actions/(.*)$ RestController.php?key=actions&id=$1 [L,nc,qsa]
# catch all non-matched requests and throw 404 or 403 accordingly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ - [R=404,NC,L]
RewriteRule ^ - [R=403,NC,L]
Por
RestController.php
ser um arquivo e não um dos seus "mapeamentos", a última regra atenderá incondicionalmente a um erro 403.Você precisa abrir uma exceção para
RestController.php
e/ou usar oEND
sinalizador (novo no Apache 2.4), em vez deL
, para impedir todo o processamento posterior das diretivas mod_rewrite. (OL
sinalizador interrompe apenas a rodada atual de processamento. Em um contexto de diretório.htaccess
, como , o URL reescrito é passado para a próxima fase de processamento e a última regra é processada durante a segunda fase.)Você também não precisa de uma regra explícita para atender ao 404, pois isso acontecerá por padrão. Você só precisa de uma regra quando a solicitação é mapeada para um arquivo (ou diretório) para atender a um erro 403.
Por exemplo, com uma exceção para
RestController.php
no último bloco de regras:Você não precisa do
L
sinalizador ao usar um status não 3xx com oR
sinalizador.Você não precisa necessariamente verificar um diretório (2ª condição), a menos que tenha um
DirectoryIndex
documento (por exemplo,index.php
ouindex.html
) nesse diretório (mas por que você faria isso?). Um 403 é atendido automaticamente pelo mod_autoindex ao solicitar um diretório semDirectoryIndex
documento.Como alternativa, ou também, use o
END
sinalizador nas regras anteriores:A
NC
bandeira não deve ser necessária aqui. Observe também que removi o$
in^file/(.*)$
, pois não é necessário (o regex é ganancioso por padrão).Aparte:
Seus "mapeamentos" podem ser reduzidos a uma única regra se você padronizar os endpoints, ou seja. Sempre um parâmetro
key
and e pode estar vazio (não "nenhum"), o que você precisaria validar de qualquer maneira (ambos e são solicitações válidas de acordo com suas regras, mas resultam em destinos diferentes). Em seguida, você valida o destino em seu script PHP.id
id
/actions
/actions/
Por exemplo:
Isso significa que
/json/<foo>
e/file
seria reescrito com sucessoRestController.php
(que de outra forma seria ignorado por suas regras originais), mas essas solicitações devem ser tratadas por sua validação de API REST de qualquer maneira. Talvez.*
devesse realmente ser.+
.