(Ou 4 siglas, 16 letras e uma dor de cabeça)
Mostrar como aplicações web ricas se comportam quando o conteúdo está vindo de uma fonte que não a fonte original.
Gerar uma view com conteúdo que será inserido em outro site; o conteúdo deverá abrir um modal para pedir mais dados para o usuário.
Carregado por AJAX, com jQuery. Fácil.
$(function() {
$("#div-especial").load("http://outrosite.com/conteudo.html");
});
Same Origin Security Policy é assegurado pelo browser, barrando requisições vindas de lugares que não são o lugar original.
"Lugar original" = URL requisitada tem mesmo esquema (http vs https), mesmo domínio (subdomínios não contam), mesma porta (ou implício 80) da URL que está fazendo a requisição.
Página em http://outrosite.com/conteudo.html
pede:
http://outrosite.com/dados.json
⇒ OKhttp://outrosite.com/dir/dados.json
⇒ OKhttp://usuário:senha@outrosite.com/dir/dados.json
⇒ OKhttp://outrosite.com:8080/dados.json
⇒ NOT!https://outrosite.com/dados.json
⇒ NOT!http://api.outrosite.com/dados.json
⇒ NOT!http://outrosite.com:80/dados.json
⇒ talvez...Apenas lembrando: isso é forçado pelo browser, não pelo serviço.
Outras aplicações podem passar por cima do Same Origin se quiserem.
Restrições de subdomínios podem ser relaxadas se scripts forem carregados de subdomínios diferentes:
Se a página em http://outrosite.com/
carregar um script de
http://api.outrosite.com
, a restrição de
subdomínios pode ser removida para funções do
script.
Se não tiver como relaxar as restrições, utiliza-se CORS.
CORS é implementado no servidor e diz se o serviço pode ou não utilizar aquele recurso.
Browser rodando em http://outrosite.com
requisita serviço em
http://api.outrosite.com/
.
Para isso, envia o header Origin
.
Origin: http://outrosite.com
Servidor olha o header, verifica se a URL tem permissão
para acessar os recursos, é retornado o header
Access-Control-Allow-Origin
.
Access-Control-Allow-Origin: http://outrosite.com
De novo, isso é controlado pelo browser; um browser que não siga corretamente o controle de acesso ou um aplicativo qualquer poderiam passar por cima dessa restrição e continuar lendo o conteúdo.
App para configurar CORS sozinho.
CORS_ORIGIN_WHITELIST = (
'outrosite.com',
)
ou
CORS_ORIGIN_REGEX_WHITELIST = (
'^(https?://)?(\w+\.)?outrosite\.com$',
)
Agora o site externo consegue carregar o conteúdo das views.
Para resolver URLs, usamos a tag {% url vew_id %}
para retornar a URL da view.
O problema é que é retornada a URL absoluta para a view, sem considerar o domínio da view.
<a href='/view/'>
em http://outrosite.com
vira
http://outrosite.com/view/
.
Mas se a view estiver num domínio diferente, o mesmo não é considerado.
http://outrosite.com
carregar o conteúdo
de http://api.outrosite.com
http://api.outrosite.com
tiver uma view
com URL absoluta /view/
http://outrosite.com/view/
http://api.outrosite.com/view/
.Solução: considerar que SITE_URL
(do
settings.py
) está correto e usar nas URLs.
<a href='{{ settings.SITE_URL }}{% url "view_id" %}'>
Resumo:
Problema: Informações do token é passada num cookie.
Set-Cookie: "csrftoken=t5HBi8EbkPk340nnpkdb8qxQsy2n8LwY;
expires=Tue, 04-Aug-2015 16:40:38 GMT; Max-Age=31449600; Path=/"
Cookies não são processados durante requisições AJAX.
Solução correta:
Ao receber uma requisição AJAX, processar os headers também, verificar a existência de "Set-Cookie", verificar se "csrftoken" está na lista, guardar o valor e usar nas requisições seguintes.
Solução utilizada:
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def minha_view(request):
....
class MinhaView(View):
@csrf_exempt
def post(self, request):
....
... não funciona.
É preciso aplicar decorators no dispatch da view:
@csrf_exempt
def dispatch(self, *args, **kwargs):
u"""Altera o dispatch para dispensar CSRF (por cauxa do AJAX)."""
return super(MinhaView, self).dispatch(*args, **kwargs)