mirror of
https://github.com/TurTaskProject/TurTaskWeb.git
synced 2025-12-19 05:54:07 +01:00
Fix Google Login / Restyle Login-Logout
This commit is contained in:
parent
f032ae50d6
commit
67829fc292
@ -46,19 +46,19 @@ INSTALLED_APPS = [
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
|
||||
'tasks',
|
||||
'django.contrib.sites',
|
||||
|
||||
'tasks',
|
||||
'users',
|
||||
'rest_framework',
|
||||
|
||||
'corsheaders',
|
||||
|
||||
'django.contrib.sites',
|
||||
'allauth',
|
||||
'allauth.account',
|
||||
'allauth.socialaccount',
|
||||
'allauth.socialaccount.providers.google',
|
||||
|
||||
'rest_framework',
|
||||
'dj_rest_auth',
|
||||
'dj_rest_auth.registration',
|
||||
'rest_framework.authtoken',
|
||||
@ -70,10 +70,10 @@ REST_FRAMEWORK = {
|
||||
|
||||
],
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': [
|
||||
'rest_framework.authentication.BasicAuthentication',
|
||||
'rest_framework.authentication.TokenAuthentication',
|
||||
'rest_framework_simplejwt.authentication.JWTAuthentication',
|
||||
'dj_rest_auth.jwt_auth.JWTCookieAuthentication',
|
||||
'rest_framework.authentication.BasicAuthentication',
|
||||
'rest_framework.authentication.SessionAuthentication',
|
||||
]
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ CORS_ALLOWED_ORIGINS = [
|
||||
"http://localhost:5173",
|
||||
]
|
||||
|
||||
CSRF_TRUSTED_ORIGINS = ["http://*"]
|
||||
CSRF_TRUSTED_ORIGINS = ["http://localhost:5173"]
|
||||
|
||||
CORS_ORIGIN_WHITELIST = ["*"]
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ class CustomUserSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = CustomUser
|
||||
fields = ('email', 'username', 'password')
|
||||
fields = ('email', 'password')
|
||||
extra_kwargs = {'password': {'write_only': True}}
|
||||
|
||||
def create(self, validated_data):
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
from django.urls import path
|
||||
from rest_framework_simplejwt import views as jwt_views
|
||||
from .views import ObtainTokenPairWithCustomView, CustomUserCreate, GreetingView, GoogleLogin
|
||||
from .views import ObtainTokenPairWithCustomView, CustomUserCreate, GreetingView, GoogleLogin, GoogleRetrieveUserInfo
|
||||
|
||||
urlpatterns = [
|
||||
path('user/create/', CustomUserCreate.as_view(), name="create_user"),
|
||||
@ -9,4 +9,5 @@ urlpatterns = [
|
||||
path('token/custom_obtain/', ObtainTokenPairWithCustomView.as_view(), name='token_create_custom'),
|
||||
path('hello/', GreetingView.as_view(), name='hello_world'),
|
||||
path('dj-rest-auth/google/', GoogleLogin.as_view(), name="google_login"),
|
||||
path('auth/google/', GoogleRetrieveUserInfo.as_view())
|
||||
]
|
||||
@ -1,16 +1,25 @@
|
||||
"""This module defines API views for authentication, user creation, and a simple hello message."""
|
||||
|
||||
from django.shortcuts import render
|
||||
import json
|
||||
import requests
|
||||
|
||||
from django.contrib.auth.hashers import make_password
|
||||
|
||||
from rest_framework import status
|
||||
from rest_framework.permissions import IsAuthenticated, AllowAny
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from dj_rest_auth.registration.views import SocialLoginView
|
||||
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
|
||||
from .adapter import CustomGoogleOAuth2Adapter
|
||||
from .serializers import MyTokenObtainPairSerializer, CustomUserSerializer
|
||||
from rest_framework_simplejwt.tokens import RefreshToken
|
||||
|
||||
from allauth.socialaccount.providers.google.views import GoogleOAuth2Adapter
|
||||
from allauth.socialaccount.providers.oauth2.client import OAuth2Client
|
||||
|
||||
from dj_rest_auth.registration.views import SocialLoginView
|
||||
|
||||
from .serializers import MyTokenObtainPairSerializer, CustomUserSerializer
|
||||
from .managers import CustomAccountManager
|
||||
from .models import CustomUser
|
||||
|
||||
|
||||
class ObtainTokenPairWithCustomView(APIView):
|
||||
"""
|
||||
@ -78,5 +87,47 @@ class GoogleLogin(SocialLoginView):
|
||||
"""
|
||||
# permission_classes = (AllowAny,)
|
||||
adapter_class = GoogleOAuth2Adapter
|
||||
client_class = OAuth2Client
|
||||
# callback_url = 'http://localhost:8000/accounts/google/login/callback/'
|
||||
# client_class = OAuth2Client
|
||||
# callback_url = 'http://localhost:8000/accounts/google/login/callback/'
|
||||
|
||||
|
||||
class GoogleRetrieveUserInfo(APIView):
|
||||
"""
|
||||
Retrieve user information from Google and create a user if not exists.
|
||||
"""
|
||||
def post(self, request):
|
||||
access_token = request.data.get("token")
|
||||
|
||||
user_info = self.get_google_user_info(access_token)
|
||||
|
||||
if 'error' in user_info:
|
||||
error_message = 'Wrong Google token or the token has expired.'
|
||||
return Response({'message': error_message, 'error': user_info['error']})
|
||||
|
||||
user = self.get_or_create_user(user_info)
|
||||
token = RefreshToken.for_user(user)
|
||||
|
||||
response = {
|
||||
'username': user.username,
|
||||
'access_token': str(token.access_token),
|
||||
'refresh_token': str(token),
|
||||
}
|
||||
|
||||
return Response(response)
|
||||
|
||||
def get_google_user_info(self, access_token):
|
||||
url = 'https://www.googleapis.com/oauth2/v2/userinfo'
|
||||
payload = {'access_token': access_token}
|
||||
response = requests.get(url, params=payload)
|
||||
return json.loads(response.text)
|
||||
|
||||
def get_or_create_user(self, user_info):
|
||||
try:
|
||||
user = CustomUser.objects.get(email=user_info['email'])
|
||||
except CustomUser.DoesNotExist:
|
||||
user = CustomUser()
|
||||
user.username = user_info['email']
|
||||
user.password = make_password(CustomAccountManager().make_random_password())
|
||||
user.email = user_info['email']
|
||||
user.save()
|
||||
return user
|
||||
@ -16,6 +16,7 @@
|
||||
"@material-ui/icons": "^4.11.3",
|
||||
"@mui/icons-material": "^5.14.15",
|
||||
"@mui/material": "^5.14.15",
|
||||
"@mui/system": "^5.14.15",
|
||||
"@react-oauth/google": "^0.11.1",
|
||||
"axios": "^1.5.1",
|
||||
"bootstrap": "^5.3.2",
|
||||
|
||||
@ -23,6 +23,9 @@ dependencies:
|
||||
'@mui/material':
|
||||
specifier: ^5.14.15
|
||||
version: 5.14.15(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0)
|
||||
'@mui/system':
|
||||
specifier: ^5.14.15
|
||||
version: 5.14.15(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.33)(react@18.2.0)
|
||||
'@react-oauth/google':
|
||||
specifier: ^0.11.1
|
||||
version: 0.11.1(react-dom@18.2.0)(react@18.2.0)
|
||||
|
||||
@ -24,10 +24,10 @@
|
||||
|
||||
import './App.css';
|
||||
import {BrowserRouter, Route, Routes, Link} from "react-router-dom";
|
||||
import Login from "./components/login";
|
||||
import TestAuth from './components/testAuth';
|
||||
import Signup from './components/signup';
|
||||
import IconSideNav from "./components/IconSideNav";
|
||||
import AuthenticantionPage from "./components/authentication/AuthenticationPage"
|
||||
import SignUpPage from "./components/authentication/SignUpPage"
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
@ -41,14 +41,14 @@ const App = () => {
|
||||
</nav>
|
||||
<Routes>
|
||||
<Route path={"/"} render={() => <h1>This is Home page!</h1>} />
|
||||
<Route path="/login" element={<Login/>}/>
|
||||
<Route path="/signup" element={<Signup/>}/>
|
||||
<Route path="/login" element={<AuthenticantionPage/>}/>
|
||||
<Route path="/signup" element={<SignUpPage/>}/>
|
||||
<Route path="/testAuth" element={<TestAuth/>}/>
|
||||
</Routes>
|
||||
</div>
|
||||
<div>
|
||||
{/* <div>
|
||||
<IconSideNav />
|
||||
</div>
|
||||
</div> */}
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
||||
|
||||
@ -62,13 +62,12 @@ const apiUserLogout = () => {
|
||||
}
|
||||
|
||||
// Function for Google login
|
||||
const googleLogin = async (accesstoken) => {
|
||||
const googleLogin = async (token) => {
|
||||
axios.defaults.withCredentials = true
|
||||
let res = await axios.post(
|
||||
"http://localhost:8000/api/dj-rest-auth/google/",
|
||||
"http://localhost:8000/api/auth/google/",
|
||||
{
|
||||
access_token: accesstoken,
|
||||
id_token: accesstoken,
|
||||
token: token,
|
||||
}
|
||||
);
|
||||
// console.log('service google login res: ', res);
|
||||
|
||||
214
frontend/src/components/authentication/AuthenticationPage.jsx
Normal file
214
frontend/src/components/authentication/AuthenticationPage.jsx
Normal file
@ -0,0 +1,214 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useGoogleLogin } from '@react-oauth/google';
|
||||
|
||||
import Avatar from '@mui/material/Avatar';
|
||||
import Button from '@mui/material/Button';
|
||||
import CssBaseline from '@mui/material/CssBaseline';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
import Checkbox from '@mui/material/Checkbox';
|
||||
import Link from '@mui/material/Link';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import Box from '@mui/material/Box';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
||||
|
||||
import axiosapi from '../../api/axiosapi';
|
||||
|
||||
|
||||
function Copyright(props) {
|
||||
return (
|
||||
<Typography variant="body2" color="text.secondary" align="center" {...props}>
|
||||
{'Copyright © '}
|
||||
<Link color="inherit" href="https://mui.com/">
|
||||
Your Website
|
||||
</Link>{' '}
|
||||
{new Date().getFullYear()}
|
||||
{'.'}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
const defaultTheme = createTheme();
|
||||
|
||||
export default function SignInSide() {
|
||||
|
||||
const Navigate = useNavigate();
|
||||
|
||||
const [email, setEmail] = useState("");
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
|
||||
const handleUsernameChange = (event) => {
|
||||
setUsername(event.target.value);
|
||||
}
|
||||
|
||||
const handleEmailChange = (event) => {
|
||||
setEmail(event.target.value);
|
||||
}
|
||||
|
||||
const handlePasswordChange = (event) => {
|
||||
setPassword(event.target.value);
|
||||
}
|
||||
|
||||
const handleSubmit = (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
// Send a POST request to the authentication API
|
||||
axiosapi.apiUserLogin({
|
||||
email: email,
|
||||
username: username,
|
||||
password: password
|
||||
}).then(res => {
|
||||
// On successful login, store tokens and set the authorization header
|
||||
localStorage.setItem('access_token', res.data.access);
|
||||
localStorage.setItem('refresh_token', res.data.refresh);
|
||||
axiosapi.axiosInstance.defaults.headers['Authorization'] = "Bearer " + res.data.access;
|
||||
Navigate('/testAuth');
|
||||
}).catch(err => {
|
||||
console.log('Login failed'); // Handle login failure
|
||||
console.log(err)
|
||||
});
|
||||
}
|
||||
|
||||
const responseGoogle = async (response) => {
|
||||
// Handle Google login response
|
||||
let googleResponse = await axiosapi.googleLogin(response.access_token);
|
||||
console.log('Google Response:\n', googleResponse);
|
||||
|
||||
if (googleResponse.status === 200) {
|
||||
// Store Google login tokens and set the authorization header on success
|
||||
localStorage.setItem('access_token', googleResponse.data.access_token);
|
||||
localStorage.setItem('refresh_token', googleResponse.data.refresh_token);
|
||||
axiosapi.axiosInstance.defaults.headers['Authorization'] = "Bearer " + googleResponse.data.access_token;
|
||||
Navigate('/testAuth');
|
||||
}
|
||||
}
|
||||
|
||||
const googleLoginImplicit = useGoogleLogin({
|
||||
// flow: 'auth-code',
|
||||
onSuccess: async (response) => {
|
||||
console.log(response);
|
||||
|
||||
try {
|
||||
const loginResponse = await axiosapi.googleLogin(response.access_token);
|
||||
if (loginResponse && loginResponse.data) {
|
||||
const { access_token, refresh_token } = loginResponse.data;
|
||||
|
||||
// Save the tokens in localStorage
|
||||
localStorage.setItem('access_token', access_token);
|
||||
localStorage.setItem('refresh_token', refresh_token);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error with the POST request:', error);
|
||||
}
|
||||
},
|
||||
onError: errorResponse => console.log(errorResponse),
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={defaultTheme}>
|
||||
<Grid container component="main" sx={{ height: '100vh' }}>
|
||||
<CssBaseline />
|
||||
<Grid
|
||||
item
|
||||
xs={false}
|
||||
sm={4}
|
||||
md={7}
|
||||
sx={{
|
||||
backgroundImage: 'url(https://source.unsplash.com/random?wallpapers)',
|
||||
backgroundRepeat: 'no-repeat',
|
||||
backgroundColor: (t) =>
|
||||
t.palette.mode === 'light' ? t.palette.grey[50] : t.palette.grey[900],
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
}}
|
||||
/>
|
||||
<Grid item xs={12} sm={8} md={5} component={Paper} elevation={6} square>
|
||||
<Box
|
||||
sx={{
|
||||
my: 8,
|
||||
mx: 4,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
|
||||
<LockOutlinedIcon />
|
||||
</Avatar>
|
||||
<Typography component="h1" variant="h5">
|
||||
Sign in
|
||||
</Typography>
|
||||
<Box component="form" noValidate onSubmit={handleSubmit} sx={{ mt: 1 }}>
|
||||
<TextField
|
||||
margin="normal"
|
||||
required
|
||||
fullWidth
|
||||
id="email"
|
||||
label="Email Address"
|
||||
name="email"
|
||||
autoComplete="email"
|
||||
autoFocus
|
||||
onChange={handleEmailChange}
|
||||
/>
|
||||
<TextField
|
||||
margin="normal"
|
||||
required
|
||||
fullWidth
|
||||
name="password"
|
||||
label="Password"
|
||||
type="password"
|
||||
id="password"
|
||||
autoComplete="current-password"
|
||||
onChange={handlePasswordChange}
|
||||
/>
|
||||
<FormControlLabel
|
||||
control={<Checkbox value="remember" color="primary" />}
|
||||
label="Remember me"
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
sx={{ mt: 3, mb: 2 }}
|
||||
>
|
||||
Sign In
|
||||
</Button>
|
||||
<Divider>OR</Divider>
|
||||
<Box py={2}>
|
||||
<Button
|
||||
fullWidth
|
||||
variant="outlined"
|
||||
color="secondary"
|
||||
onClick={() => googleLoginImplicit()}
|
||||
>
|
||||
Sign in with Google 🚀
|
||||
</Button>
|
||||
</Box>
|
||||
<Grid container>
|
||||
<Grid item xs>
|
||||
<Link href="#" variant="body2">
|
||||
Forgot password?
|
||||
</Link>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Link href="#" variant="body2">
|
||||
{"Don't have an account? Sign Up"}
|
||||
</Link>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Copyright sx={{ mt: 5 }} />
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
146
frontend/src/components/authentication/SignUpPage.jsx
Normal file
146
frontend/src/components/authentication/SignUpPage.jsx
Normal file
@ -0,0 +1,146 @@
|
||||
import React, { useState } from 'react';
|
||||
import axiosapi from '../../api/axiosapi';
|
||||
|
||||
import Avatar from '@mui/material/Avatar';
|
||||
import Button from '@mui/material/Button';
|
||||
import CssBaseline from '@mui/material/CssBaseline';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||
import Checkbox from '@mui/material/Checkbox';
|
||||
import Link from '@mui/material/Link';
|
||||
import Grid from '@mui/material/Grid';
|
||||
import Box from '@mui/material/Box';
|
||||
import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Container from '@mui/material/Container';
|
||||
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
||||
|
||||
|
||||
function Copyright(props) {
|
||||
return (
|
||||
<Typography variant="body2" color="text.secondary" align="center" {...props}>
|
||||
{'Copyright © '}
|
||||
<Link color="inherit" href="https://mui.com/">
|
||||
Your Website
|
||||
</Link>{' '}
|
||||
{new Date().getFullYear()}
|
||||
{'.'}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
const defaultTheme = createTheme();
|
||||
|
||||
export default function SignUp() {
|
||||
const [formData, setFormData] = useState({
|
||||
email: '',
|
||||
username: '',
|
||||
password: '',
|
||||
});
|
||||
const [error, setError] = useState(null);
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
axiosapi.createUser(formData);
|
||||
} catch (error) {
|
||||
console.error('Error creating user:', error);
|
||||
setError('Registration failed. Please try again.');
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (e) => {
|
||||
const { name, value } = e.target;
|
||||
setFormData({ ...formData, [name]: value });
|
||||
};
|
||||
|
||||
return (
|
||||
<ThemeProvider theme={defaultTheme}>
|
||||
<Container component="main" maxWidth="xs">
|
||||
<CssBaseline />
|
||||
<Box
|
||||
sx={{
|
||||
marginTop: 8,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
|
||||
<LockOutlinedIcon />
|
||||
</Avatar>
|
||||
<Typography component="h1" variant="h5">
|
||||
Sign up
|
||||
</Typography>
|
||||
<Box component="form" noValidate onSubmit={handleSubmit} sx={{ mt: 3 }}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
required
|
||||
fullWidth
|
||||
id="email"
|
||||
label="Email Address"
|
||||
name="email"
|
||||
autoComplete="email"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
autoComplete="username"
|
||||
name="Username"
|
||||
required
|
||||
fullWidth
|
||||
id="Username"
|
||||
label="Username"
|
||||
autoFocus
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<TextField
|
||||
required
|
||||
fullWidth
|
||||
name="password"
|
||||
label="Password"
|
||||
type="password"
|
||||
id="password"
|
||||
autoComplete="new-password"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs={12}>
|
||||
<FormControlLabel
|
||||
control={<Checkbox value="allowExtraEmails" color="primary" />}
|
||||
label="I want to receive inspiration, marketing promotions and updates via email."
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
sx={{ mt: 3, mb: 2 }}
|
||||
>
|
||||
Sign Up
|
||||
</Button>
|
||||
<Grid container justifyContent="flex-end">
|
||||
<Grid item>
|
||||
<Link href="#" variant="body2">
|
||||
Already have an account? Sign in
|
||||
</Link>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Box>
|
||||
</Box>
|
||||
<Copyright sx={{ mt: 5 }} />
|
||||
</Container>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
@ -1,161 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import Avatar from '@material-ui/core/Avatar';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import CssBaseline from '@material-ui/core/CssBaseline';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
import Container from '@material-ui/core/Container';
|
||||
import axiosapi from '../api/axiosapi';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useGoogleLogin } from '@react-oauth/google';
|
||||
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
// Styles for various elements
|
||||
paper: {
|
||||
marginTop: theme.spacing(8),
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
},
|
||||
avatar: {
|
||||
margin: theme.spacing(1),
|
||||
backgroundColor: theme.palette.secondary.main,
|
||||
},
|
||||
form: {
|
||||
width: '100%',
|
||||
marginTop: theme.spacing(1),
|
||||
},
|
||||
submit: {
|
||||
margin: theme.spacing(3, 0, 2),
|
||||
},
|
||||
}));
|
||||
|
||||
export default function Login() {
|
||||
const history = useNavigate();
|
||||
const classes = useStyles();
|
||||
|
||||
const [email, setEmail] = useState("");
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
|
||||
const handleUsernameChange = (event) => {
|
||||
// Update the 'username' state when the input field changes
|
||||
setUsername(event.target.value);
|
||||
}
|
||||
|
||||
const handleEmailChange = (event) => {
|
||||
// Update the 'email' state when the email input field changes
|
||||
setEmail(event.target.value);
|
||||
}
|
||||
|
||||
const handlePasswordChange = (event) => {
|
||||
// Update the 'password' state when the password input field changes
|
||||
setPassword(event.target.value);
|
||||
}
|
||||
|
||||
const handleSubmit = (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
// Send a POST request to the authentication API
|
||||
axiosapi.apiUserLogin({
|
||||
email: email,
|
||||
username: username,
|
||||
password: password
|
||||
}).then(res => {
|
||||
// On successful login, store tokens and set the authorization header
|
||||
localStorage.setItem('access_token', res.data.access);
|
||||
localStorage.setItem('refresh_token', res.data.refresh);
|
||||
axiosapi.axiosInstance.defaults.headers['Authorization'] = "Bearer " + res.data.access;
|
||||
history.push('/testAuth');
|
||||
}).catch(err => {
|
||||
console.log('Login failed'); // Handle login failure
|
||||
console.log(err)
|
||||
});
|
||||
}
|
||||
|
||||
const responseGoogle = async (response) => {
|
||||
// Handle Google login response
|
||||
let googleResponse = await axiosapi.googleLogin(response.access_token);
|
||||
console.log('Google Response:\n', googleResponse);
|
||||
|
||||
if (googleResponse.status === 200) {
|
||||
// Store Google login tokens and set the authorization header on success
|
||||
localStorage.setItem('access_token', googleResponse.data.access_token);
|
||||
localStorage.setItem('refresh_token', googleResponse.data.refresh_token);
|
||||
axiosapi.axiosInstance.defaults.headers['Authorization'] = "Bearer " + googleResponse.data.access_token;
|
||||
history.push('/testAuth');
|
||||
}
|
||||
}
|
||||
|
||||
const googleLoginflow = useGoogleLogin({
|
||||
onSuccess: async tokenResponse => {
|
||||
console.log(tokenResponse);
|
||||
responseGoogle(tokenResponse);
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
<Container component="main" maxWidth="xs">
|
||||
<CssBaseline />
|
||||
<div className={classes.paper}>
|
||||
<Avatar className={classes.avatar} />
|
||||
<Typography component="h1" variant="h5">
|
||||
Sign in
|
||||
</Typography>
|
||||
<form className={classes.form} noValidate onSubmit={handleSubmit}>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
required
|
||||
fullWidth
|
||||
id="email"
|
||||
label="Email"
|
||||
name="email"
|
||||
autoComplete="email"
|
||||
autoFocus
|
||||
onChange={handleEmailChange}
|
||||
/>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
required
|
||||
fullWidth
|
||||
id="username"
|
||||
label="Username"
|
||||
name="username"
|
||||
autoComplete="username"
|
||||
autoFocus
|
||||
onChange={handleUsernameChange}
|
||||
/>
|
||||
<TextField
|
||||
variant="outlined"
|
||||
margin="normal"
|
||||
required
|
||||
fullWidth
|
||||
name="password"
|
||||
label="Password"
|
||||
type="password"
|
||||
id="password"
|
||||
autoComplete="current-password"
|
||||
onChange={handlePasswordChange}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
fullWidth
|
||||
variant="contained"
|
||||
color="primary"
|
||||
className={classes.submit}
|
||||
>
|
||||
Sign In
|
||||
</Button>
|
||||
</form>
|
||||
|
||||
|
||||
<button onClick={() => googleLoginflow()}>
|
||||
Sign in with Google 🚀{' '}
|
||||
</button>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
@ -8,4 +8,7 @@ djangorestframework>=3.14
|
||||
markdown>=3.5
|
||||
django-filter>=23.3
|
||||
djangorestframework-simplejwt>=5.3
|
||||
django-cors-headers>=4.3
|
||||
django-cors-headers>=4.3
|
||||
google_api_python_client>=2.1
|
||||
google_auth_oauthlib>=1.1
|
||||
google-auth-httplib2>=0.1
|
||||
Loading…
Reference in New Issue
Block a user