禁止(未设置 CSRF cookie。)Django、Next.js

问题描述 投票:0回答:1

我正在尝试将数据发布到 Django 服务器,以便从 Next.js 应用程序更新用户配置文件;

我对其他路线也有类似的设置,它们工作得很好, 但在这里我收到以下错误:

禁止(未设置 CSRF cookie。):/users/api/update-profile/ [2024年12月15日20:53:02]“发布/users/api/update-profile/HTTP/1.1”403 2855

#settings.py

CSRF_COOKIE_HTTPONLY = False  # Allow JavaScript to read the CSRF cookie
#CSRF_USE_SESSIONS = False
CSRF_COOKIE_SAMESITE = 'Lax'
CSRF_COOKIE_SECURE = False
# Ensure these are set correctly
SESSION_COOKIE_SAMESITE = 'Lax'  # or 'None' for cross-site
CSRF_COOKIE_SAMESITE = 'Lax'     # or 'None' for cross-site

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
CORS_ALLOW_CREDENTIALS = True
#CORS_ALLOW_ALL_ORIGINS = True

CORS_ALLOWED_ORIGINS = [
    #"http://localhost",  
    #"http://127.0.0.1", 
    "http://localhost:3000" 
]

CORS_ALLOW_METHODS = [
    'DELETE',
    'GET',
    'OPTIONS',
    'PATCH',
    'POST',
    'PUT',
]

CORS_ALLOW_HEADERS = [
    'accept',
    'accept-encoding',
    'authorization',
    'content-type',
    'dnt',
    'origin',
    'user-agent',
    'x-csrftoken',
    'x-requested-with',
]

#views.py

@login_required
def update_profile(request):
    if request.method == 'POST':
        user = request.user
        print('user', user)
        # Gender validation
        if 'gender' in request.POST:
            gender = request.POST.get('gender')
            if gender in dict(user.gender_choices):
                user.gender = gender
        
        # Username validation
        if 'username' in request.POST:
            username = request.POST.get('username')
            if len(username) <= 50 and not User.objects.exclude(pk=user.pk).filter(username=username).exists():
                user.username = username
            else:
                return JsonResponse({'status': 'error', 'message': 'Invalid or duplicate username'})
        
        # Password validation
        if 'password' in request.POST:
            password = request.POST.get('password')
            if len(password) <= 50:
                user.password = make_password(password)
                # If you want to keep the user logged in after password change
                update_session_auth_hash(request, user)
            else:
                return JsonResponse({'status': 'error', 'message': 'Password too long'})
        
        # Email validation
        if 'email' in request.POST:
            email = request.POST.get('email')
            try:
                validate_email(email)
                if not User.objects.exclude(pk=user.pk).filter(email=email).exists():
                    user.email = email
                else:
                    return JsonResponse({'status': 'error', 'message': 'Email already exists'})
            except ValidationError:
                return JsonResponse({'status': 'error', 'message': 'Invalid email format'})
        
        # Phone validation
        if 'phone' in request.POST:
            phone = request.POST.get('phone')
            if len(phone) <= 50:
                user.phone = phone
        
        # Date of birth validation
        if 'date_of_birth' in request.POST:
            try:
                date_of_birth = datetime.strptime(request.POST.get('date_of_birth'), '%Y-%m-%d').date()
                user.date_of_birth = date_of_birth
            except ValueError:
                return JsonResponse({'status': 'error', 'message': 'Invalid date format. Use YYYY-MM-DD'})
        
        # Zodiac sign validation
        if 'zodiac_sign' in request.POST:
            zodiac_sign = request.POST.get('zodiac_sign')
            if len(zodiac_sign) <= 50:
                user.zodiac_sign = zodiac_sign
        
        # Religion validation
        if 'religion' in request.POST:
            religion = request.POST.get('religion')
            if len(religion) <= 100:
                user.religion = religion
        
        # Bio validation
        if 'bio' in request.POST:
            bio = request.POST.get('bio')
            if len(bio) <= 500:
                user.bio = bio
        
        # Location validation
        if 'location' in request.POST:
            location = request.POST.get('location')
            if len(location) <= 255:
                user.location = location
        
        # Profile picture link validation
        if 'profile_picture_link' in request.POST:
            profile_picture_link = request.POST.get('profile_picture_link')
            if len(profile_picture_link) <= 1000:
                user.profile_picture_link = profile_picture_link
        
        # Profile picture file validation
        if 'profile_picture' in request.FILES:
            profile_picture = request.FILES.get('profile_picture')
            user.profile_picture = profile_picture
        
        # Onboarded and Premium status (typically not updated via user input)
        if 'onboarded' in request.POST:
            user.onboarded = request.POST.get('onboarded') == 'True'
        
        if 'is_premium' in request.POST:
            user.is_premium = request.POST.get('is_premium') == 'True'
        
        try: # Additional model-level validation
            user.save()
            return JsonResponse({
                'status': 'success', 
                'message': 'Profile updated successfully',
                'updated_fields': list(request.POST.keys())
            })
        except ValidationError as e:
            return JsonResponse({
                'status': 'error', 
                'message': 'Validation failed',
                'errors': e.message_dict
            })
    
    
    # If not a POST request, return current user data
    return JsonResponse({
        'user': {
            'username': user.username,
            'email': user.email,
            # Add other fields as needed
        }
    })

#updateprofile/route.ts

import { LogInCredentials } from "@/interfaces/user";
import { API_URL } from "@/lib/constants";
import { extractCsrfToken, extractSessionId } from "@/lib/sessionidextractor";
import { NextApiRequest, NextApiResponse } from "next";
import { cookies } from 'next/headers'
import { NextRequest } from "next/server";


export async function POST( req: NextApiRequest, res: NextApiResponse) {
    console.log('i am reaching here')
    const Cookies = await cookies()

    const csrfToken = Cookies.getAll('csrftoken')
    const sessionid = Cookies.getAll('sessionid')

    console.log('CSRF Token:', csrfToken)
    console.log('sessionid:', sessionid)


    const profileUpdateResponse = await fetch(`${API_URL}/update-profile/`, {
        method: 'POST',
        headers:{
            'Content-Type': 'application/json',
            'X-CSRFToken': `${csrfToken[0].value}`,
            'Cookie': `${sessionid[0].value}`
        },
        body: JSON.stringify(req.body)
      });

    
    const responseText = await profileUpdateResponse.text()
    //console.log(responseText)

    if(profileUpdateResponse.status == 403){
       
        return Response.json({}, {status: 400})
    }

    if(profileUpdateResponse.status == 401){
        console.log('400000000',profileUpdateResponse.status)
        return Response.json({}, {status: 400})
    }
    if(profileUpdateResponse.status == 200 || profileUpdateResponse.status == 302){

        return Response.json({}, {status: 200})
    }
    return Response.json({'response': true},{status: 200})
 
    
}
python reactjs django typescript next.js
1个回答
0
投票

Cookie 处理: 我设置 Cookie 标头的方式可能不正确。通常,您希望将其设置为完整的 cookie 字符串:

   const profileUpdateResponse = await fetch(`${API_URL}/update-profile/${requestBody.user_id}/`, {
      method: 'POST',
      credentials: 'include',
      headers: {
        'Content-Type': 'application/json',
        'X-CSRFToken': csrfToken.value,
        'Cookie': `csrftoken=${csrfToken.value}; sessionid=${sessionid.value}`
      },
  body: JSON.stringify(requestBody)
});
© www.soinside.com 2019 - 2024. All rights reserved.