Pol*_*der 5 django-rest-framework google-oauth google-api-python-client django-allauth django-rest-auth
I'm trying to implement Google authentication in django with allauth and rest-auth. After many hours of research, none of the solutions I found worked in my project.
I based my code on a github issue: https://github.com/Tivix/django-rest-auth/issues/403
And an article: https://medium.com/@gonzafirewall/google-oauth2-and-django-rest-auth-92b0d8f70575
I have also created a Social Application object with Google client id and client secret
Authorized JavaScript origins: http://localhost:8000 Authorized redirect URIs: http://localhost:8000/api/v1/users/login/google/callback/
providers.py:
from allauth.socialaccount.providers.google.provider import GoogleProvider
class GoogleProviderMod(GoogleProvider):
def extract_uid(self, data):
return str(data['sub'])
Run Code Online (Sandbox Code Playgroud)
adapters.py:
from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
from google.auth.transport import requests
from google.oauth2 import id_token
from myproj.users.providers import GoogleProviderMod
class GoogleOAuth2AdapterIdToken(GoogleOAuth2Adapter):
provider_id = GoogleProviderMod.id
def complete_login(self, request, app, token, **kwargs):
idinfo = id_token.verify_oauth2_token(token.token, requests.Request(), app.client_id)
if idinfo["iss"] not in ["accounts.google.com", "https://accounts.google.com"]:
raise ValueError("Wrong issuer.")
extra_data = idinfo
login = self.get_provider().sociallogin_from_response(request, extra_data)
return login
Run Code Online (Sandbox Code Playgroud)
views.py:
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from rest_auth.registration.serializers import SocialLoginSerializer
from rest_auth.registration.views import SocialLoginView
from myproj.users.adapters import GoogleOAuth2AdapterIdToken
class GoogleLoginView(SocialLoginView):
adapter_class = GoogleOAuth2AdapterIdToken
callback_url = "http://localhost:8000/api/v1/users/login/google/callback/"
client_class = OAuth2Client
serializer_class = SocialLoginSerializer
Run Code Online (Sandbox Code Playgroud)
urls.py:
from allauth.socialaccount.providers.oauth2.views import OAuth2CallbackView
from django.urls import path
from myproj.users.adapters import GoogleOAuth2AdapterIdToken
from myproj.users.views import GoogleLoginView
app_name = "users"
urlpatterns = [
path(
"login/google/",
GoogleLoginView.as_view(),
name="google_login"
),
path(
"login/google/callback/",
OAuth2CallbackView.adapter_view(GoogleOAuth2AdapterIdToken),
name="google_callback"
),
]
Run Code Online (Sandbox Code Playgroud)
settings.py:
AUTHENTICATION_BACKENDS = [
"django.contrib.auth.backends.ModelBackend",
"allauth.account.auth_backends.AuthenticationBackend",
]
ACCOUNT_DEFAULT_HTTP_PROTOCOL = "http"
Run Code Online (Sandbox Code Playgroud)
When I passing ID Token (returned from Google 'sign in' button) as code parameter on login page, the error occurring:
allauth.socialaccount.providers.oauth2.client.OAuth2Error: Error retrieving access token: b'{\n "error": "invalid_grant",\n "error_description": "Malformed auth code."\n}'
Response code is 400.
Actually, even if I passing some random text to the code, the error is the same.
Thanks for help!
我还集成了djangorestframework + django-allauth + django-rest-auth + djangorestframework-jwt。但是,我只是实现了Signin with Google,所以用户不能手动注册。
这是我的代码:
视图.py
from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from rest_auth.registration.views import SocialLoginView
class GoogleLogin(SocialLoginView):
adapter_class = GoogleOAuth2Adapter
client_class = OAuth2Client
Run Code Online (Sandbox Code Playgroud)
网址.py
...
path('auth/google', GoogleLogin.as_view(), name='google_login'),
...
Run Code Online (Sandbox Code Playgroud)
设置.py
INSTALLED_APPS = [
...
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.google',
...
]
SITE_ID = 1
REST_USE_JWT = True # this is for djangorestframework-jwt
Run Code Online (Sandbox Code Playgroud)
[更新]在 SocialLoginView 端点上
使用code参数:
https://accounts.google.com/o/oauth2/v2/auth?redirect_uri=<https_callback>&prompt=consent&response_type=code&client_id=<cliend_id>&scope=email&access_type=offline小智 0
您是否在项目的开发人员控制台中添加了 UI 的本地主机地址?我正在尝试使用 Google 身份验证执行类似于您的设置的操作。我最终在 Django 中创建了另一个应用程序,该应用程序对于一个特定的路由不受 csrf 约束,以便在使用有效令牌调用时注册(更新或创建)用户。
class VerifyToken(APIView):
permission_classes = (AllowAny,) # maybe not needed in your case
authentication_classes = (UnsafeSessionAuthentication,)
@csrf_exempt
def post(self, request):
print('hitting endpoint')
requestJson = json.loads(request.body)
request = requests.Request()
id_info = id_token.verify_oauth2_token(requestJson['token'], request, settings.CLIENT_ID)
if id_info['iss'] not in ['accounts.google.com', 'https://accounts.google.com']:
return Response("Unable to Validate User: Wrong Issuer")
# raise ValueError('Wrong issuer.')
if not id_info:
return Response("Unable to Validate User: Invalid Token")
# raise Exception("Unable to Validate Token")
id = id_info['email']
user_letters = id_info['given_name'][0].upper() + id_info['family_name'][0].upper()
# In this case, if the Person already exists, its name is updated
user, created = User.objects.update_or_create(
email=id, defaults={
"first_name": id_info['given_name'],
"last_name": id_info['family_name'],
"last_login": datetime.datetime.now(),
"email_verified": id_info['email_verified'],
"exp": id_info['exp'],
"locale": id_info['locale'],
"name": id_info['name'],
"picture": id_info['picture'],
"initials": user_letters,
"username": id_info['given_name'] + " " + id_info['family_name'],
}
)
if created:
serializer = UserSerializer(user)
return Response(serializer.data)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
708 次 |
| 最近记录: |