Реализация Django и React с использованием Google OAuth2 не работает с csrftoken
Я реализовал бэкенд Django для процесса авторизации пользователя через Google OAuth2 signin/signup.
Механизм запускается из React UI.
Пользователь может успешно зарегистрироваться, используя бэкенд Django, и я вижу, что связанные пользователи созданы в Django Admin.
Однако, когда я пытаюсь использовать ту же информацию о пользователе через React UI, вызов API "me" не может получить доступ к пользователю Django, который вошел в систему. Но прямой вызов Django через браузер и команду curl работает нормально.
Следующая команда работает нормально с вызовом бэкенда :
curl -X GET --header "Cookie: csrftoken=M1kFFNataWZcbckfdrqUEiXuRRsSRwYKKCH4XvENUyWnLE9xnSMHe7DiaUcDBRU6; sessionid=p156z2d5gy9cwamojxvmxbopg84p99v6" http://localhost:8000/registration/me/
Ниже приведены настройки Django для Cors и CSRF :
CORS_ORIGIN_ALLOW_ALL = True
ALLOWED_HOSTS = ['*']
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000",
]
CORS_ALLOW_ALL_ORIGINS=True
CORS_ALLOW_CREDENTIALS = False
CORS_ORIGIN_WHITELIST = [
'http://localhost:3000'
]
CSRF_COOKIE_NAME = "csrftoken"
CSRF_COOKIE_HTTPONLY = False
CORS_EXPOSE_HEADERS = ["Content-Type", "X-CSRFToken"]
CORS_ALLOW_CREDENTIALS = True
CSRF_COOKIE_AGE = None
CSRF_COOKIE_DOMAIN = 'localhost'
CSRF_COOKIE_HTTPONLY = True
CSRF_COOKIE_SECURE = True
CSRF_USE_SESSIONS = True
Ниже приведены остальные настройки фреймворка :
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
'DEFAULT_PERMISSIONS_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}
Вызов API от Django для "меня" :
@api_view(['GET'])
def current_user(request):
from rest_framework.permissions import IsAuthenticated
permission_classes = [IsAuthenticated]
user = request.user
if user.is_authenticated:
return Response({
'username' : user.username,
'email' : user.email,
'firstname' : user.first_name,
'lastname' : user.last_name,
'picture' : user.picture,
'email_verified' : user.email_verified,
'locale' : user.locale,
'token' : user.token
})
return Response({'user' : 'anonymous'})
Ниже приводится звонок Axios :
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
console.log("COOKIE : " + document.cookie);
var cookieValue = document.cookie
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken').split("=")[1];
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.xsrfCookieName = "csrftoken";
axios({
method: 'get',
url: 'http://localhost:8000/registration/me/',
data: {
csrfmiddlewaretoken: csrftoken,
'Authentication' : "Token " + csrftoken,
},
headers: {
"Content-Type": "X-CSRFToken",
'X-CSRFTOKEN' : "M1kFFNataWZcbckfdrqUEiXuRRsSRwYKKCH4XvENUyWnLE9xnSMHe7DiaUcDBRU6",
},
withCredentials: false,
xsrfHeaderName: 'X-CSRFToken',
xsrfCookieName: 'csrftoken',
}).then(res => {
resultState.state = 'success';
resultState.data = res.data;
console.log("registration/me success : " + JSON.stringify(resultState.data));
}).catch((err) => {
resultState.state = 'error';
resultState.data['message'] = err.message;
console.log("registration/me error : " + JSON.stringify(resultState.data));
})
Реакция на вызов Django выглядит следующим образом :
registration/me success : {"user":"anonymous"}
Я могу предоставить любую дополнительную информацию о настройке. Любые предложения будут оценены по достоинству.
На самом деле все необходимое было на месте, достаточно было только установить параметр "withCredentials : true". Страница уже знала cookie / связанного пользователя, но axios не использовал информацию cookie автоматически.
Добавление параметра, как указано ниже, было достаточным :
axios({
method: 'get',
url: 'http://localhost:8000/registration/me/',
withCredentials: true,
}).then(res => {
resultState.state = 'success';
resultState.data = res.data;
}).catch((err) => {
resultState.state = 'error';
resultState.data['message'] = err.message;
})