英文:
Vue Django app Forbidden (CSRF cookie not set.): 403 Forbidden
问题
I suppose this would actually be a django question as I think there's something wrong with the backend. I have my Vue code in frontend/ (127.0.0.1:8080) and django code in backend/ (127.0.0.1:8000). I've followed the django docs on CORS and CSRF Tokens but I get Forbidden (CSRF cookie not set.):
when trying to make a post request to the django server. I'm trying to reset password via email.
backend/settings.py:
...
CORS_ALLOW_ALL_ORIGINS = True # If this is used then `CORS_ALLOWED_ORIGINS` will not have any effect
CORS_ALLOW_CREDENTIALS = True
CSRF_TRUSTED_ORIGINS = [
'http://127.0.0.1:8080',
]
CORS_ALLOWED_ORIGINS = [
'http://127.0.0.1:8080',
]
# SESSION_COOKIE_SAMESITE = 'None'
# CORS_ALLOW_CREDENTIALS = True
EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_DIR = BASE_DIR / 'emails'
...
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework.authtoken',
'corsheaders',
'djoser',
'product',
'order',
'email_app'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
...
backend/urls.py:
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('djoser.urls')),
path('api/v1/', include('djoser.urls.authtoken')),
path('api/v1/', include('product.urls')),
path('api/v1/', include('order.urls')),
path('api/v1/', include('email_app.urls'))
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
backend/email_app/urls.py:
from django.urls import path
from email_app import views
urlpatterns = [
path('reset_password/', views.reset_password),
]
backend/email_app/views.py:
from rest_framework.decorators import api_view
from django.core.mail import send_mail
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
from django.template.loader import render_to_string
from rest_framework.response import Response
from rest_framework import status
from django.middleware.csrf import get_token
from django.views.decorators.csrf import csrf_protect
from rest_framework import status
from rest_framework.decorators import api_view
from .serializers import ResetPasswordEmail
@api_view(['POST', 'GET'])
@csrf_protect
def reset_password(request):
if request.method == "POST":
serializer = ResetPasswordEmail(data=request.data)
if serializer.is_valid():
# get the email from Front-End
email = serializer.validated_data['email']
# find the user that has that email
user = User.objects.get(email=email)
# get the token of that user
token = Token.objects.get(user=user)
if user:
# pass the context of things above to send them in an email
context = {
'email': email,
'username': user,
'token': token
}
send_mail(
'd-commerce Password Reset',
render_to_string('emails/reset_password.txt', context),
'D-COMMERCE and No Reply',
[email],
fail_silently=False,
auth_user=None, auth_password=None, connection=None, html_message=None
)
serializer.save(token=token, slug=token)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
...
For vue I use:
...
// using jQuery
getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
...
and using axios to send the request:
...
const csrftoken = this.getCookie('csrftoken');
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
axios.defaults.headers.common['X-CSRFToken'] = csrftoken;
axios.post("/api/v1/reset_password/", formData)
.then(response => {
toast({message: 'If you have an account with us,
please check your email for the link!',
type: 'is-success',
dismissible: true,
pauseOnHover: true,
position: 'bottom-right',})
})
...
英文:
I suppose this would actually be a django question as I think there's something wrong with the backend. I have my Vue code in frontend/ (127.0.0.1:8080) and django code in backend/ (127.0.0.1:8000). I've followed the django docs on CORS and CSRF Tokens but I get Forbidden (CSRF cookie not set.):
when trying to make a post request to the django server. I'm trying to reset password via email.
backend/settings.py
...
CORS_ALLOW_ALL_ORIGINS = True # If this is used then `CORS_ALLOWED_ORIGINS` will not have any effect
CORS_ALLOW_CREDENTIALS = True
CSRF_TRUSTED_ORIGINS = [
'http://127.0.0.1:8080',
]
CORS_ALLOWED_ORIGINS = [
'http://127.0.0.1:8080',
]
# SESSION_COOKIE_SAMESITE = 'None'
# CORS_ALLOW_CREDENTIALS = True
EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_DIR = BASE_DIR / 'emails'
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework.authtoken',
'corsheaders',
'djoser',
'product',
'order',
'email_app'
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
...
backend/urls.py:
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include('djoser.urls')),
path('api/v1/', include('djoser.urls.authtoken')),
path('api/v1/', include('product.urls')),
path('api/v1/', include('order.urls')),
path('api/v1/', include('email_app.urls'))
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
backend/email_app/urls.py:
from django.urls import path
from email_app import views
urlpatterns = [
path('reset_password/', views.reset_password),
]
backend/email_app/views.py:
from rest_framework.decorators import api_view
from django.core.mail import send_mail
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
from django.template.loader import render_to_string
from rest_framework.response import Response
from rest_framework import status
from django.middleware.csrf import get_token
from django.views.decorators.csrf import csrf_protect
from rest_framework import status
from rest_framework.decorators import api_view
from .serializers import ResetPasswordEmail
@api_view(['POST', 'GET'])
@csrf_protect
def reset_password(request):
if request.method == "POST":
serializer = ResetPasswordEmail(data=request.data)
if serializer.is_valid():
# get the email from Front-End
email = serializer.validated_data['email']
# find the user that has that email
user = User.objects.get(email=email)
# get the token of that user
token = Token.objects.get(user=user)
if user:
# pass the context of things above to send them in an email
context = {
'email': email,
'username': user,
'token': token
}
send_mail(
'd-commerce Password Reset',
render_to_string('emails/reset_password.txt', context),
'D-COMMERCE and No Reply',
[email],
fail_silently=False,
auth_user=None, auth_password=None, connection=None, html_message=None
)
serializer.save(token=token, slug=token)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
...
For vue I use:
...
// using jQuery
getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
...
and using axios to send the request:
...
const csrftoken = this.getCookie('csrftoken');
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
axios.defaults.headers.common['X-CSRFToken'] = csrftoken;
axios.post("/api/v1/reset_password/", formData)
.then(response => {
toast({message: 'If you have an account with us,
please check your email for the link!',
type: 'is-success',
dismissible: true,
pauseOnHover: true,
position: 'bottom-right',})
})
...
答案1
得分: 0
这似乎是修复的方法,我添加了 withCredentials = true
并设置了头部如下:
axios.defaults.withCredentials = true;
axios.defaults.headers.common = {
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken' : this.getCookie('csrftoken')
};
英文:
Ok so this seems to be the fix, I added withCredentials = true
and set the headers like this:
axios.defaults.withCredentials = true;
axios.defaults.headers.common = {
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken' : this.getCookie('csrftoken')
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论