Vue Django应用程序 Forbidden (CSRF cookie not set.): 403 Forbidden

huangapple go评论95阅读模式
英文:

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:

  1. ...
  2. CORS_ALLOW_ALL_ORIGINS = True # If this is used then `CORS_ALLOWED_ORIGINS` will not have any effect
  3. CORS_ALLOW_CREDENTIALS = True
  4. CSRF_TRUSTED_ORIGINS = [
  5. 'http://127.0.0.1:8080',
  6. ]
  7. CORS_ALLOWED_ORIGINS = [
  8. 'http://127.0.0.1:8080',
  9. ]
  10. # SESSION_COOKIE_SAMESITE = 'None'
  11. # CORS_ALLOW_CREDENTIALS = True
  12. EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
  13. EMAIL_FILE_DIR = BASE_DIR / 'emails'
  14. ...
  15. # Application definition
  16. INSTALLED_APPS = [
  17. 'django.contrib.admin',
  18. 'django.contrib.auth',
  19. 'django.contrib.contenttypes',
  20. 'django.contrib.sessions',
  21. 'django.contrib.messages',
  22. 'django.contrib.staticfiles',
  23. 'rest_framework',
  24. 'rest_framework.authtoken',
  25. 'corsheaders',
  26. 'djoser',
  27. 'product',
  28. 'order',
  29. 'email_app'
  30. ]
  31. MIDDLEWARE = [
  32. 'django.middleware.security.SecurityMiddleware',
  33. 'django.contrib.sessions.middleware.SessionMiddleware',
  34. 'corsheaders.middleware.CorsMiddleware',
  35. 'django.middleware.common.CommonMiddleware',
  36. 'django.middleware.csrf.CsrfViewMiddleware',
  37. 'django.contrib.auth.middleware.AuthenticationMiddleware',
  38. 'django.contrib.messages.middleware.MessageMiddleware',
  39. 'django.middleware.clickjacking.XFrameOptionsMiddleware',
  40. ]
  41. ...

backend/urls.py:

  1. urlpatterns = [
  2. path('admin/', admin.site.urls),
  3. path('api/v1/', include('djoser.urls')),
  4. path('api/v1/', include('djoser.urls.authtoken')),
  5. path('api/v1/', include('product.urls')),
  6. path('api/v1/', include('order.urls')),
  7. path('api/v1/', include('email_app.urls'))
  8. ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

backend/email_app/urls.py:

  1. from django.urls import path
  2. from email_app import views
  3. urlpatterns = [
  4. path('reset_password/', views.reset_password),
  5. ]

backend/email_app/views.py:

  1. from rest_framework.decorators import api_view
  2. from django.core.mail import send_mail
  3. from django.contrib.auth.models import User
  4. from rest_framework.authtoken.models import Token
  5. from django.template.loader import render_to_string
  6. from rest_framework.response import Response
  7. from rest_framework import status
  8. from django.middleware.csrf import get_token
  9. from django.views.decorators.csrf import csrf_protect
  10. from rest_framework import status
  11. from rest_framework.decorators import api_view
  12. from .serializers import ResetPasswordEmail
  13. @api_view(['POST', 'GET'])
  14. @csrf_protect
  15. def reset_password(request):
  16. if request.method == "POST":
  17. serializer = ResetPasswordEmail(data=request.data)
  18. if serializer.is_valid():
  19. # get the email from Front-End
  20. email = serializer.validated_data['email']
  21. # find the user that has that email
  22. user = User.objects.get(email=email)
  23. # get the token of that user
  24. token = Token.objects.get(user=user)
  25. if user:
  26. # pass the context of things above to send them in an email
  27. context = {
  28. 'email': email,
  29. 'username': user,
  30. 'token': token
  31. }
  32. send_mail(
  33. 'd-commerce Password Reset',
  34. render_to_string('emails/reset_password.txt', context),
  35. 'D-COMMERCE and No Reply',
  36. [email],
  37. fail_silently=False,
  38. auth_user=None, auth_password=None, connection=None, html_message=None
  39. )
  40. serializer.save(token=token, slug=token)
  41. return Response(serializer.data, status=status.HTTP_201_CREATED)
  42. return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  43. ...

For vue I use:

  1. ...
  2. // using jQuery
  3. getCookie(name) {
  4. var cookieValue = null;
  5. if (document.cookie && document.cookie !== '') {
  6. var cookies = document.cookie.split(';');
  7. for (var i = 0; i < cookies.length; i++) {
  8. var cookie = jQuery.trim(cookies[i]);
  9. // Does this cookie string begin with the name we want?
  10. if (cookie.substring(0, name.length + 1) === (name + '=')) {
  11. cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
  12. break;
  13. }
  14. }
  15. }
  16. return cookieValue;
  17. }
  18. ...

and using axios to send the request:

  1. ...
  2. const csrftoken = this.getCookie('csrftoken');
  3. axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
  4. axios.defaults.headers.common['X-CSRFToken'] = csrftoken;
  5. axios.post("/api/v1/reset_password/", formData)
  6. .then(response => {
  7. toast({message: 'If you have an account with us,
  8. please check your email for the link!',
  9. type: 'is-success',
  10. dismissible: true,
  11. pauseOnHover: true,
  12. position: 'bottom-right',})
  13. })
  14. ...
英文:

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

  1. ...
  2. CORS_ALLOW_ALL_ORIGINS = True # If this is used then `CORS_ALLOWED_ORIGINS` will not have any effect
  3. CORS_ALLOW_CREDENTIALS = True
  4. CSRF_TRUSTED_ORIGINS = [
  5. &#39;http://127.0.0.1:8080&#39;,
  6. ]
  7. CORS_ALLOWED_ORIGINS = [
  8. &#39;http://127.0.0.1:8080&#39;,
  9. ]
  10. # SESSION_COOKIE_SAMESITE = &#39;None&#39;
  11. # CORS_ALLOW_CREDENTIALS = True
  12. EMAIL_BACKEND = &#39;django.core.mail.backends.filebased.EmailBackend&#39;
  13. EMAIL_FILE_DIR = BASE_DIR / &#39;emails&#39;
  14. # Application definition
  15. INSTALLED_APPS = [
  16. &#39;django.contrib.admin&#39;,
  17. &#39;django.contrib.auth&#39;,
  18. &#39;django.contrib.contenttypes&#39;,
  19. &#39;django.contrib.sessions&#39;,
  20. &#39;django.contrib.messages&#39;,
  21. &#39;django.contrib.staticfiles&#39;,
  22. &#39;rest_framework&#39;,
  23. &#39;rest_framework.authtoken&#39;,
  24. &#39;corsheaders&#39;,
  25. &#39;djoser&#39;,
  26. &#39;product&#39;,
  27. &#39;order&#39;,
  28. &#39;email_app&#39;
  29. ]
  30. MIDDLEWARE = [
  31. &#39;django.middleware.security.SecurityMiddleware&#39;,
  32. &#39;django.contrib.sessions.middleware.SessionMiddleware&#39;,
  33. &#39;corsheaders.middleware.CorsMiddleware&#39;,
  34. &#39;django.middleware.common.CommonMiddleware&#39;,
  35. &#39;django.middleware.csrf.CsrfViewMiddleware&#39;,
  36. &#39;django.contrib.auth.middleware.AuthenticationMiddleware&#39;,
  37. &#39;django.contrib.messages.middleware.MessageMiddleware&#39;,
  38. &#39;django.middleware.clickjacking.XFrameOptionsMiddleware&#39;,
  39. ]
  40. ...

backend/urls.py:

  1. urlpatterns = [
  2. path(&#39;admin/&#39;, admin.site.urls),
  3. path(&#39;api/v1/&#39;, include(&#39;djoser.urls&#39;)),
  4. path(&#39;api/v1/&#39;, include(&#39;djoser.urls.authtoken&#39;)),
  5. path(&#39;api/v1/&#39;, include(&#39;product.urls&#39;)),
  6. path(&#39;api/v1/&#39;, include(&#39;order.urls&#39;)),
  7. path(&#39;api/v1/&#39;, include(&#39;email_app.urls&#39;))
  8. ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

backend/email_app/urls.py:

  1. from django.urls import path
  2. from email_app import views
  3. urlpatterns = [
  4. path(&#39;reset_password/&#39;, views.reset_password),
  5. ]

backend/email_app/views.py:

  1. from rest_framework.decorators import api_view
  2. from django.core.mail import send_mail
  3. from django.contrib.auth.models import User
  4. from rest_framework.authtoken.models import Token
  5. from django.template.loader import render_to_string
  6. from rest_framework.response import Response
  7. from rest_framework import status
  8. from django.middleware.csrf import get_token
  9. from django.views.decorators.csrf import csrf_protect
  10. from rest_framework import status
  11. from rest_framework.decorators import api_view
  12. from .serializers import ResetPasswordEmail
  13. @api_view([&#39;POST&#39;, &#39;GET&#39;])
  14. @csrf_protect
  15. def reset_password(request):
  16. if request.method == &quot;POST&quot;:
  17. serializer = ResetPasswordEmail(data=request.data)
  18. if serializer.is_valid():
  19. # get the email from Front-End
  20. email = serializer.validated_data[&#39;email&#39;]
  21. # find the user that has that email
  22. user = User.objects.get(email=email)
  23. # get the token of that user
  24. token = Token.objects.get(user=user)
  25. if user:
  26. # pass the context of things above to send them in an email
  27. context = {
  28. &#39;email&#39;: email,
  29. &#39;username&#39;: user,
  30. &#39;token&#39;: token
  31. }
  32. send_mail(
  33. &#39;d-commerce Password Reset&#39;,
  34. render_to_string(&#39;emails/reset_password.txt&#39;, context),
  35. &#39;D-COMMERCE and No Reply&#39;,
  36. [email],
  37. fail_silently=False,
  38. auth_user=None, auth_password=None, connection=None, html_message=None
  39. )
  40. serializer.save(token=token, slug=token)
  41. return Response(serializer.data, status=status.HTTP_201_CREATED)
  42. return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  43. ...

For vue I use:

  1. ...
  2. // using jQuery
  3. getCookie(name) {
  4. var cookieValue = null;
  5. if (document.cookie &amp;&amp; document.cookie !== &#39;&#39;) {
  6. var cookies = document.cookie.split(&#39;;&#39;);
  7. for (var i = 0; i &lt; cookies.length; i++) {
  8. var cookie = jQuery.trim(cookies[i]);
  9. // Does this cookie string begin with the name we want?
  10. if (cookie.substring(0, name.length + 1) === (name + &#39;=&#39;)) {
  11. cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
  12. break;
  13. }
  14. }
  15. }
  16. return cookieValue;
  17. }
  18. ...

and using axios to send the request:

  1. ...
  2. const csrftoken = this.getCookie(&#39;csrftoken&#39;);
  3. axios.defaults.headers.common[&#39;X-Requested-With&#39;] = &#39;XMLHttpRequest&#39;;
  4. axios.defaults.headers.common[&#39;X-CSRFToken&#39;] = csrftoken;
  5. axios.post(&quot;/api/v1/reset_password/&quot;, formData)
  6. .then(response =&gt; {
  7. toast({message: &#39;If you have an account with us,
  8. please check your email for the link!&#39;,
  9. type: &#39;is-success&#39;,
  10. dismissible: true,
  11. pauseOnHover: true,
  12. position: &#39;bottom-right&#39;,})
  13. })
  14. ...

答案1

得分: 0

这似乎是修复的方法,我添加了 withCredentials = true 并设置了头部如下:

  1. axios.defaults.withCredentials = true;
  2. axios.defaults.headers.common = {
  3. 'X-Requested-With': 'XMLHttpRequest',
  4. 'X-CSRFToken' : this.getCookie('csrftoken')
  5. };
英文:

Ok so this seems to be the fix, I added withCredentials = true and set the headers like this:

  1. axios.defaults.withCredentials = true;
  2. axios.defaults.headers.common = {
  3. &#39;X-Requested-With&#39;: &#39;XMLHttpRequest&#39;,
  4. &#39;X-CSRFToken&#39; : this.getCookie(&#39;csrftoken&#39;)
  5. };

huangapple
  • 本文由 发表于 2023年6月25日 22:43:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76550956.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定