Реализация google login с помощью django
У меня есть django приложение, в котором я хочу развернуть google login auth. Моим фронтенд-фреймворком является flutter. После входа с помощью flutter в google, он отправляет auth_code, полученный от google, на бэкенд django. Вот как я реализую свой логин
google_auth_request = HttpRequestManager()
class GoogleAuth:
def __init__(self, code):
self.code = code
def get_access_token(self, code: str, redirect_uri: str) -> str:
data = {
"code": code,
"client_id": config.settings.constants.GOOGLE_AUTH_CONFIG["GOOGLE_OAUTH2_CLIENT_ID"],
"client_secret": config.settings.constants.GOOGLE_AUTH_CONFIG["GOOGLE_OAUTH2_CLIENT_SECRET"],
"redirect_uri": redirect_uri,
"grant_type": "authorization_code",
}
response = google_auth_request.post(
config.settings.constants.GOOGLE_AUTH_CONFIG["GOOGLE_ACCESS_TOKEN_OBTAIN_URL"], data=data
)
if not response.ok:
log.error("Response.json() for get access_token")
log.error(response.json())
print(response.json(), flush=True)
raise ValidationError("Could not get access token from Google.")
access_token = response.json()["access_token"]
return access_token
def get_user_info(self, access_token: str) -> Dict[str, Any]:
response = google_auth_request.get(
config.settings.constants.GOOGLE_AUTH_CONFIG["GOOGLE_USER_INFO_URL"], params={"access_token": access_token}
)
if not response.ok:
log.error(f"google auth response data: {response.data}")
print(response.json(), flush=True)
raise Exception("google service is unavailable")
return response.json()
def login(self):
domain = config.settings.constants.GOOGLE_AUTH_CONFIG["GOOGLE_OAUTH2_API_URL"]
redirect_uri = f"{domain}/api/auth/v1/login/google/"
access_token = self.get_access_token(code=self.code, redirect_uri=redirect_uri)
user_data = self.get_user_info(access_token)
# Creates user in DB if first time login
query = EtloUser.objects.filter(email=user_data["email"])
if not query.exists():
EtloUser.objects.create(
email=user_data["email"],
first_name=user_data.get("given_name"),
last_name=user_data.get("family_name"),
)
profile_data = {
"email": user_data["email"],
"first_name": user_data.get("given_name"),
"last_name": user_data.get("family_name"),
}
return profile_data
И это его вид
@extend_schema(request=GoogleAuthSerializer, responses={200: OutputCredentialSerializer})
class GoogleAuthView(APIView):
throttle_scope = "auth"
def post(self, request, *args, **kwargs):
auth_serializer = GoogleAuthSerializer(data=request.data)
auth_serializer.is_valid(raise_exception=True)
validated_data = auth_serializer.validated_data
if validated_data["error"] or not validated_data["code"]:
params = urlencode({"error": validated_data["error"]})
return redirect(f"{config.settings.constants.GOOGLE_AUTH_CONFIG['GOOGLE_OAUTH2_LOGIN_URL']}?{params}")
google_auth_service = GoogleAuth(validated_data["code"])
user_profile = google_auth_service.login()
auth_backend = EtloGoogleAuthenticationBackend(user_profile["email"])
user = auth_backend.authenticate_credentials()
tokens = auth_backend.get_user_tokens_data(user)
return Response(tokens, status=status.HTTP_200_OK)
Но когда flutter отправляет auth_code на django, выводится строка print(response.json(), flush=True): {'error': 'invalid_grant', 'error_description': 'Bad Request'}
Ваш curl запрос неправильно сформирован, вы не можете передать информацию oauth в качестве параметров запроса.
invalid_grant
Предоставленный код авторизации недействителен или имеет неправильный формат. Запросите новый код, перезапустив процесс OAuth, чтобы снова попросить пользователя дать согласие.
А вот правильный формат:
POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencodedcode=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=ваш_клиент_id&
client_secret=ваш_клиентский_секрет&
redirect_uri=https%3A//oauth2.example.com/code&
grant_type=authorization_code
Что в переводе на curl выглядит следующим образом:
curl -X POST https://oauth2.googleapis.com/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7" \
-d "client_id=your_client_id" \
-d "client_secret=your_client_secret" \
-d "redirect_uri=https%3A//oauth2.example.com/code" \
-d "grant_type=authorization_code"
Что касается вашего кода на Python, то, возможно, дело в отсутствии заголовка Content-Type, который указан в документации.
Предполагая, что HttpRequestManager соответствует requests:
[...]
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
response = google_auth_request.post(config.settings.constants.GOOGLE_AUTH_CONFIG["GOOGLE_ACCESS_TOKEN_OBTAIN_URL"],
data=data,
headers=headers
)