"Forbidden (CSRF cookie not set.)" 在 Django 开发环境中使用没有有效证书的 https
"Forbidden (CSRF cookie not set.)" in Django dev env using https without valid certificate
很确定这就是我在开发环境中遇到 Forbidden (CSRF cookie not set.)
错误的原因:
- 正在处理 Azure AD 身份验证
- URI 重定向需要
localhost
或 https://
- 因为我在本地
k8s
集群中开发 skaffold
,它有一个 minikube ip
像 192.168.64.7
- 因此,我不得不为我的 URI 重定向做
https://192.168.64.7/
而不是使用有效的 SSL 证书,因为我只是在开发中
- 我正在将
accessToken
从 React FE 发送到我们的 API 以便在那里再次验证它
- 非常确定 Django 正在检测
https://
并且它无效导致此错误
所以我的问题是:
- 我对出现此错误的原因是否正确?
- 有没有我可以在开发中启用的设置来忽略这个?
- 或者是我为我的开发环境获取有效 SSL 证书的唯一选择?
我已确认执行以下操作无效:
ALLOWED_HOSTS = [
'*'
]
此外,GET
请求有效,但 POST
无效。
#views.py
from django.shortcuts import render
from django.views import View
from django.http import HttpResponse
# Create your views here.
class TestView(View):
def post(self, request):
return HttpResponse('Hello World')
// Authentication.js
const testApiAuthentication = async () => {
let accessToken = await authProvider.getAccessToken();
setAccessToken(accessToken.accessToken);
if (accessToken) {
setAuthenticatingToken(true);
axios({
method: 'post',
url: '/api/users/',
headers: {
Authorization: 'Bearer ' + accessToken,
},
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
}
};
编辑:
一个选项(但不是一个好选项)是免除 CSRF。
from django.views import View
from django.http import HttpResponse
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
# Create your views here.
@method_decorator(csrf_exempt, name='dispatch')
class TestView(View):
def post(self, request):
return HttpResponse('Hello World')
同样,这样做不是一个好主意...
我确实设法为我的开发环境实施了一个证书,认为它可以解决问题,但它仍然存在。
建议?
原来问题是我需要使用 django-rest-framework
,因为根据我的阅读,它内置了 CSRF 豁免。我想我会使用 Django 视图来快速测试它,但是原来是导致问题的原因。 需要使用DRF。
以下内容仅供参考,以防在 class-based 视图上有 @csrf_exempt
或在本地开发 k8s 集群中实施 TLS 的任何人有所帮助。
正如我所指出的,一种选择(而不是一个好的选择)是将其从 CSRF 中豁免。
from django.views import View
from django.http import HttpResponse
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
# Create your views here.
@method_decorator(csrf_exempt, name='dispatch')
class TestView(View):
def post(self, request):
return HttpResponse('Hello World')
对我有用的 TLS 实现如下(主要基于 this blog article):
- 确定您要为您的应用提供的 DNS 名称并将其添加到
/etc/hosts
并将其映射到 minikube ip
(是的,不幸的是,如果您执行 minikube delete
).在我的例子中是:
192.168.64.7 companyapp.local
然后刷新您的本地 DNS。在 macOS 上是:
sudo killall -HUP mDNSResponder
- 更新您的开发
ingress-nginx.yaml
以使用 hosts
。我最初并没有在我的开发入口中这样做。我最终得到:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: 'nginx'
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite ^(/admin)$ / permanent;
name: ingress-service-dev
namespace: default
spec:
tls:
- hosts:
- companyapp.local
secretName: tls-companyapp-dev
rules:
- host: companyapp.local
http:
paths:
- path: /admin/
backend:
serviceName: admin-cluster-ip-service-dev
servicePort: 4000
- path: /api/
backend:
serviceName: api-cluster-ip-service-dev
servicePort: 5000
- path: /
backend:
serviceName: client-cluster-ip-service-dev
servicePort: 3000
- 安装
mkcert
并生成证书(请参阅 link 以获取您的 OS):
brew install mkcert
brew install nss # if you use Firefox
mkcert -install
mkcert companyapp.local
- 安装
cert-manager
:
# Kubernetes 1.16+
$ kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.0.4/cert-manager.yaml
# Kubernetes <1.16
$ kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.0.4/cert-manager-legacy.yaml
等待 Pods 准备好检查:
kubectl get pods --namespace cert-manager
- 使用来自
mkcert
: 的证书创建一个 k8s 秘密条目
kubectl create secret tls tls-companyapp-dev --key=companyapp.local-key.pem --cert=companyapp.local.pem
执行此操作后您应该能够删除 .pem
个文件。
- 制作
Issuer
和 Certificate
清单并应用它们:
# issuer.yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-dev-issuer
namespace: cert-manager
spec:
ca:
secretName: tls-companyapp-dev
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: letsencrypt-dev-certificate
namespace: cert-manager
spec:
secretName: tls-companyapp-dev
dnsNames:
- companyapp.local
issuerRef:
name: letsencrypt-dev-issuer
kind: Issuer
并将它们应用于:
kubectl apply -f <manifest_location>/issuer.yaml
尝试了几次,但最终我能够导航到 companyapp.local
并且它有一个有效的证书。不必再处理“不安全”消息。
说了这么多……还是没有解决我的问题。
很确定这就是我在开发环境中遇到 Forbidden (CSRF cookie not set.)
错误的原因:
- 正在处理 Azure AD 身份验证
- URI 重定向需要
localhost
或https://
- 因为我在本地
k8s
集群中开发skaffold
,它有一个minikube ip
像192.168.64.7
- 因此,我不得不为我的 URI 重定向做
https://192.168.64.7/
而不是使用有效的 SSL 证书,因为我只是在开发中 - 我正在将
accessToken
从 React FE 发送到我们的 API 以便在那里再次验证它 - 非常确定 Django 正在检测
https://
并且它无效导致此错误
所以我的问题是:
- 我对出现此错误的原因是否正确?
- 有没有我可以在开发中启用的设置来忽略这个?
- 或者是我为我的开发环境获取有效 SSL 证书的唯一选择?
我已确认执行以下操作无效:
ALLOWED_HOSTS = [
'*'
]
此外,GET
请求有效,但 POST
无效。
#views.py
from django.shortcuts import render
from django.views import View
from django.http import HttpResponse
# Create your views here.
class TestView(View):
def post(self, request):
return HttpResponse('Hello World')
// Authentication.js
const testApiAuthentication = async () => {
let accessToken = await authProvider.getAccessToken();
setAccessToken(accessToken.accessToken);
if (accessToken) {
setAuthenticatingToken(true);
axios({
method: 'post',
url: '/api/users/',
headers: {
Authorization: 'Bearer ' + accessToken,
},
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
}
};
编辑:
一个选项(但不是一个好选项)是免除 CSRF。
from django.views import View
from django.http import HttpResponse
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
# Create your views here.
@method_decorator(csrf_exempt, name='dispatch')
class TestView(View):
def post(self, request):
return HttpResponse('Hello World')
同样,这样做不是一个好主意...
我确实设法为我的开发环境实施了一个证书,认为它可以解决问题,但它仍然存在。
建议?
原来问题是我需要使用 django-rest-framework
,因为根据我的阅读,它内置了 CSRF 豁免。我想我会使用 Django 视图来快速测试它,但是原来是导致问题的原因。 需要使用DRF。
以下内容仅供参考,以防在 class-based 视图上有 @csrf_exempt
或在本地开发 k8s 集群中实施 TLS 的任何人有所帮助。
正如我所指出的,一种选择(而不是一个好的选择)是将其从 CSRF 中豁免。
from django.views import View
from django.http import HttpResponse
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
# Create your views here.
@method_decorator(csrf_exempt, name='dispatch')
class TestView(View):
def post(self, request):
return HttpResponse('Hello World')
对我有用的 TLS 实现如下(主要基于 this blog article):
- 确定您要为您的应用提供的 DNS 名称并将其添加到
/etc/hosts
并将其映射到minikube ip
(是的,不幸的是,如果您执行minikube delete
).在我的例子中是:
192.168.64.7 companyapp.local
然后刷新您的本地 DNS。在 macOS 上是:
sudo killall -HUP mDNSResponder
- 更新您的开发
ingress-nginx.yaml
以使用hosts
。我最初并没有在我的开发入口中这样做。我最终得到:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: 'nginx'
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite ^(/admin)$ / permanent;
name: ingress-service-dev
namespace: default
spec:
tls:
- hosts:
- companyapp.local
secretName: tls-companyapp-dev
rules:
- host: companyapp.local
http:
paths:
- path: /admin/
backend:
serviceName: admin-cluster-ip-service-dev
servicePort: 4000
- path: /api/
backend:
serviceName: api-cluster-ip-service-dev
servicePort: 5000
- path: /
backend:
serviceName: client-cluster-ip-service-dev
servicePort: 3000
- 安装
mkcert
并生成证书(请参阅 link 以获取您的 OS):
brew install mkcert
brew install nss # if you use Firefox
mkcert -install
mkcert companyapp.local
- 安装
cert-manager
:
# Kubernetes 1.16+
$ kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.0.4/cert-manager.yaml
# Kubernetes <1.16
$ kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.0.4/cert-manager-legacy.yaml
等待 Pods 准备好检查:
kubectl get pods --namespace cert-manager
- 使用来自
mkcert
: 的证书创建一个 k8s 秘密条目
kubectl create secret tls tls-companyapp-dev --key=companyapp.local-key.pem --cert=companyapp.local.pem
执行此操作后您应该能够删除 .pem
个文件。
- 制作
Issuer
和Certificate
清单并应用它们:
# issuer.yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-dev-issuer
namespace: cert-manager
spec:
ca:
secretName: tls-companyapp-dev
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: letsencrypt-dev-certificate
namespace: cert-manager
spec:
secretName: tls-companyapp-dev
dnsNames:
- companyapp.local
issuerRef:
name: letsencrypt-dev-issuer
kind: Issuer
并将它们应用于:
kubectl apply -f <manifest_location>/issuer.yaml
尝试了几次,但最终我能够导航到 companyapp.local
并且它有一个有效的证书。不必再处理“不安全”消息。
说了这么多……还是没有解决我的问题。