Update Use Authorization code to exchange with token.

This commit is contained in:
sosokker 2023-11-02 00:52:39 +07:00
parent 330be0d5b8
commit 22e5b705e3
8 changed files with 85 additions and 26 deletions

View File

@ -79,11 +79,14 @@ REST_FRAMEWORK = {
REST_USE_JWT = True REST_USE_JWT = True
GOOGLE_CLIENT_ID = config('GOOGLE_CLIENT_ID', default='fake-client-id')
GOOGLE_CLIENT_SECRET = config('GOOGLE_CLIENT_SECRET', default='fake-client-secret')
SOCIALACCOUNT_PROVIDERS = { SOCIALACCOUNT_PROVIDERS = {
'google': { 'google': {
'APP': { 'APP': {
'client_id': config('GOOGLE_CLIENT_ID', default='fake-client-id'), 'client_id': GOOGLE_CLIENT_ID,
'secret': config('GOOGLE_CLIENT_SECRET', default='fake-client-secret'), 'secret': GOOGLE_CLIENT_SECRET,
'key': '' 'key': ''
}, },
"SCOPE": [ "SCOPE": [

View File

@ -9,5 +9,5 @@ urlpatterns = [
path('token/custom_obtain/', ObtainTokenPairWithCustomView.as_view(), name='token_create_custom'), path('token/custom_obtain/', ObtainTokenPairWithCustomView.as_view(), name='token_create_custom'),
path('hello/', GreetingView.as_view(), name='hello_world'), path('hello/', GreetingView.as_view(), name='hello_world'),
path('dj-rest-auth/google/', GoogleLogin.as_view(), name="google_login"), path('dj-rest-auth/google/', GoogleLogin.as_view(), name="google_login"),
path('auth/google/', GoogleRetrieveUserInfo.as_view()) path('auth/google/', GoogleRetrieveUserInfo.as_view()),
] ]

View File

@ -3,6 +3,7 @@
import json import json
import requests import requests
from django.conf import settings
from django.contrib.auth.hashers import make_password from django.contrib.auth.hashers import make_password
from rest_framework import status from rest_framework import status
@ -16,6 +17,8 @@ from allauth.socialaccount.providers.oauth2.client import OAuth2Client
from dj_rest_auth.registration.views import SocialLoginView from dj_rest_auth.registration.views import SocialLoginView
from google_auth_oauthlib.flow import InstalledAppFlow
from .serializers import MyTokenObtainPairSerializer, CustomUserSerializer from .serializers import MyTokenObtainPairSerializer, CustomUserSerializer
from .managers import CustomAccountManager from .managers import CustomAccountManager
from .models import CustomUser from .models import CustomUser
@ -96,17 +99,28 @@ class GoogleRetrieveUserInfo(APIView):
Retrieve user information from Google and create a user if not exists. Retrieve user information from Google and create a user if not exists.
""" """
permission_classes = (AllowAny,) permission_classes = (AllowAny,)
client_config = {"web":{"client_id": settings.GOOGLE_CLIENT_ID,
"project_id":"turtask","auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_secret": settings.GOOGLE_CLIENT_SECRET,
}
}
scopes = [
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/calendar.readonly',
]
def post(self, request): def post(self, request):
access_token = request.data.get("token") code = request.data.get("code")
payload = self.exchange_authorization_code(code=code)
user_info = self.get_google_user_info(access_token) if 'error' in payload:
return Response({'error': payload['error']})
if 'error' in user_info: user_info = self.call_google_api(api_url='https://www.googleapis.com/oauth2/v2/userinfo?alt=json',
error_message = 'Wrong Google token or the token has expired.' access_token=payload['access_token'])
return Response({'message': error_message, 'error': user_info['error']}) payload['email'] = user_info['email']
user = self.get_or_create_user(payload)
user = self.get_or_create_user(user_info)
token = RefreshToken.for_user(user) token = RefreshToken.for_user(user)
response = { response = {
@ -117,13 +131,32 @@ class GoogleRetrieveUserInfo(APIView):
return Response(response) return Response(response)
def get_google_user_info(self, access_token): def get(self, request):
url = 'https://www.googleapis.com/oauth2/v2/userinfo' """Get authorization url."""
payload = {'access_token': access_token} flow = InstalledAppFlow.from_client_config(client_config=self.client_config,
response = requests.get(url, params=payload) scopes=self.scopes)
flow.redirect_uri = 'http://localhost:5173/'
authorization_url, state = flow.authorization_url(
access_type='offline',
# include_granted_scopes='true',
)
return Response({'url': authorization_url})
def exchange_authorization_code(self, code):
"""Exchange authorization code for access, id, refresh token."""
url = 'https://oauth2.googleapis.com/token'
payload = {
'code': code,
'client_id': settings.GOOGLE_CLIENT_ID,
'client_secret': settings.GOOGLE_CLIENT_SECRET,
'redirect_uri': 'postmessage',
'grant_type': 'authorization_code',
}
response = requests.post(url, data=payload)
return json.loads(response.text) return json.loads(response.text)
def get_or_create_user(self, user_info): def get_or_create_user(self, user_info):
"""Get or create a user based on email."""
try: try:
user = CustomUser.objects.get(email=user_info['email']) user = CustomUser.objects.get(email=user_info['email'])
except CustomUser.DoesNotExist: except CustomUser.DoesNotExist:
@ -132,4 +165,15 @@ class GoogleRetrieveUserInfo(APIView):
user.password = make_password(CustomAccountManager().make_random_password()) user.password = make_password(CustomAccountManager().make_random_password())
user.email = user_info['email'] user.email = user_info['email']
user.save() user.save()
return user return user
def call_google_api(self, api_url, access_token):
"""Call Google API with access token."""
headers = {
'Authorization': f'Bearer {access_token}'
}
response = requests.get(api_url, headers=headers)
if response.status_code == 200:
return response.json()
raise Exception('Google API Error', response)

View File

@ -6,6 +6,7 @@ import IconSideNav from './components/IconSideNav';
import AuthenticantionPage from './components/authentication/AuthenticationPage'; import AuthenticantionPage from './components/authentication/AuthenticationPage';
import SignUpPage from './components/authentication/SignUpPage'; import SignUpPage from './components/authentication/SignUpPage';
import NavBar from './components/Nav/Navbar'; import NavBar from './components/Nav/Navbar';
import Home from './components/Home';
const App = () => { const App = () => {
@ -14,7 +15,7 @@ const App = () => {
<div className="App"> <div className="App">
<NavBar/> <NavBar/>
<Routes> <Routes>
<Route path={"/"} render={() => <h1>This is Home page!</h1>} /> <Route path="/" element={<Home/>}/>
<Route path="/login" element={<AuthenticantionPage/>}/> <Route path="/login" element={<AuthenticantionPage/>}/>
<Route path="/signup" element={<SignUpPage/>}/> <Route path="/signup" element={<SignUpPage/>}/>
<Route path="/testAuth" element={<TestAuth/>}/> <Route path="/testAuth" element={<TestAuth/>}/>

View File

@ -67,7 +67,7 @@ const googleLogin = async (token) => {
let res = await axios.post( let res = await axios.post(
"http://localhost:8000/api/auth/google/", "http://localhost:8000/api/auth/google/",
{ {
token: token, code: token,
} }
); );
// console.log('service google login res: ', res); // console.log('service google login res: ', res);

View File

@ -0,0 +1,11 @@
import React from 'react';
function HomePage() {
return (
<div>
<h1>Welcome to My Website</h1>
</div>
);
}
export default HomePage;

View File

@ -1,5 +1,5 @@
import * as React from 'react'; import * as React from 'react';
import { Link } from 'react-router-dom'; import { Link, useNavigate } from 'react-router-dom';
import IsAuthenticated from '../authentication/IsAuthenticated'; import IsAuthenticated from '../authentication/IsAuthenticated';
import axiosapi from '../../api/axiosapi'; import axiosapi from '../../api/axiosapi';
import AppBar from '@mui/material/AppBar'; import AppBar from '@mui/material/AppBar';
@ -28,6 +28,7 @@ const settings = {
}; };
function NavBar() { function NavBar() {
const Navigate = useNavigate();
const [anchorElNav, setAnchorElNav] = React.useState(null); const [anchorElNav, setAnchorElNav] = React.useState(null);
const [anchorElUser, setAnchorElUser] = React.useState(null); const [anchorElUser, setAnchorElUser] = React.useState(null);

View File

@ -1,7 +1,7 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useGoogleLogin } from '@react-oauth/google'; import { useGoogleLogin } from '@react-oauth/google';
import axios from 'axios';
import Avatar from '@mui/material/Avatar'; import Avatar from '@mui/material/Avatar';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import CssBaseline from '@mui/material/CssBaseline'; import CssBaseline from '@mui/material/CssBaseline';
@ -91,12 +91,11 @@ export default function SignInSide() {
} }
const googleLoginImplicit = useGoogleLogin({ const googleLoginImplicit = useGoogleLogin({
// flow: 'auth-code', flow: 'auth-code',
onSuccess: async (response) => { redirect_uri: 'postmessage',
console.log(response); onSuccess: async (response) => {
try { try {
const loginResponse = await axiosapi.googleLogin(response.access_token); const loginResponse = await axiosapi.googleLogin(response.code);
if (loginResponse && loginResponse.data) { if (loginResponse && loginResponse.data) {
const { access_token, refresh_token } = loginResponse.data; const { access_token, refresh_token } = loginResponse.data;