Comment configurer le nouveau Google Auth dans une application React et Express

Dans cet article, vous apprendrez à configurer le nouveau bouton « Se connecter avec Google » de Google Auth dans une application React.js et Express.js.
Cette nouvelle méthode simplifie la façon dont les développeurs implémentent Google Auth. Il apporte des avantages significatifs, tels que la possibilité pour les utilisateurs d’afficher une photo de profil afin de sélectionner le bon compte Google – ce qui évite les erreurs d’inscription et garantit que votre application ne sera pas affectée lorsque Google abandonnera l’ancien « Se connecter avec Google» Bibliothèque JavaScript le 31 mars 2023.
Il convient de noter que les ID client nouvellement créés ne peuvent plus utiliser l’ancien Bibliothèque de plate-forme et que Google Auth doit être implémenté de cette manière.
Voici le code source de cet article : Serveur et Client.
Générer un ID client et un secret Google
La première étape à suivre pour mettre en œuvre l’authentification Google consiste à générer un ID client et un secret pour l’application que vous créez.
Étape 1
On commence par se diriger vers console Google.
Étape 2
Cliquez sur le menu déroulant en surbrillance ci-dessus. Après cela, cliquez sur le nouveau projet mis en évidence ci-dessous.
Étape 3
Ajoutez un nom de projet. J’ai choisi connect-google-auth-article
.
Étape 4
Cliquez sur le menu déroulant à l’étape 1 pour sélectionner le projet.
Étape 5
L’écran suivant que vous voyez devrait ressembler à l’exemple ci-dessous. Cliquez ensuite sur le tableau de bord.
Étape 6
L’étape suivante consiste à configurer le consentement oauth. Pour y parvenir, passez la souris sur « API et services » et cliquez sur « Écran de consentement OAuth ».
Étape 7
Sélectionnez le type de consentement souhaité. J’ai choisi externe et appuyé CRÉER.
Étape 8
Une fois le consentement défini, cliquez sur les informations d’identification pour définir les détails de votre application. Étant donné que mon application est hébergée sur localhost, j’ai défini les détails comme illustré ci-dessous.
Remarque : lorsque vous êtes prêt à déployer votre application, vous devez remplacer l’URI1 et l’URI2 par le nom de domaine que vous souhaitez utiliser, par exemple https://example.com
.
Étape 9
Une fois vos informations d’identification stockées avec succès, vous pouvez copier ou télécharger l’ID client et le secret générés.
Configurer l’application React
Le moyen le plus simple de démarrer une application React.js consiste à utiliser Créer une application React.
Par conséquent, créez un dossier, nommez-le comme vous le souhaitez. Ouvrez ensuite un terminal et exécutez le code suivant : npx create-react-app app
.
Configuration du serveur express
Créez un autre dossier dans le répertoire racine. je nomme le mien server
. Ensuite, ouvrez un terminal et cd dans le serveur : cd server
.
Après cela, créez un server.js
fichier avant de générer un package.json
en exécutant npm init -y
. Ensuite, installez les packages suivants :
- Express.js : « un cadre d’application Web Node.js minimal et flexible qui fournit un ensemble robuste de fonctionnalités pour les applications Web et mobiles ».
- CORS : un package Node.js pour fournir un middleware Connect/Express qui peut être utilisé pour activer le partage de ressources cross-origin avec diverses options.
- Dotenv : un package Node.js qui charge les variables d’environnement à partir de
.env
dossier. - Google-auth-library : bibliothèque cliente d’authentification de l’API Google pour Node.js.
- Jsonwebtoken : une bibliothèque d’implémentation JSON Web Token pour Node.js.
- Nodemon : un script de surveillance simple à utiliser lors du développement d’une application Node.js.
Vous pouvez installer les packages ci-dessus en exécutant la commande suivante :
npm install express cors dotenv google-auth-library jsonwebtoken nodemon
Après cela, configurez votre script en procédant comme suit :
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
},
Ton package.json
devrait ressembler à ceci :
{
"name": "connect-google-auth-article",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
},
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^16.0.2",
"express": "^4.18.1",
"google-auth-library": "^8.5.2",
"jsonwebtoken": "^8.5.1",
"nodemon": "^2.0.20"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Après cela, écrivez le code suivant dans server.js
et courir npm run dev
pour démarrer votre serveur :
const express = require("express");
const app = express();
require("dotenv/config");
const cors = require("cors");
const { OAuth2Client } = require("google-auth-library");
const jwt = require("jsonwebtoken");
app.use(
cors({
origin: ["http://localhost:3000"],
methods: "GET,POST,PUT,DELETE,OPTIONS",
})
);
app.use(express.json());
let DB = [];
app.listen("5152", () => console.log("Server running on port 5152"));
Préparation de l’application React
Pour préparer notre application client, nous ajouterons le script Google à la tête de notre public/index.html
dossier:
<script src="https://accounts.google.com/gsi/client" async defer></script>
Notre index.html
le fichier devrait ressembler à ceci :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<script src="https://accounts.google.com/gsi/client" async defer></script>
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
Ensuite, nous allons créer deux dossiers dans notre src
: screens
et hooks
.
La screens
dossier contiendra cinq fichiers : Home.jsx
, Landing.jsx
, Login.jsx
, Signup.jsx
et index.js
. La hooks
dossier contiendra un seul fichier : useFetch.jsx
.
Configurer le routage côté client
Le package que nous utiliserons pour le routage côté client est react-router-dom
. Ouvrez un nouveau terminal, accédez à l’application et exécutez le code suivant : npm install react-router-dom
.
Nous pouvons alors mettre à jour notre App.js
ressembler à ceci :
import React, { useEffect } from "react";
import { useState } from "react";
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
const App = () => {
const [user, setUser] = useState({});
return (
<BrowserRouter>
<Routes>
</Routes>
</BrowserRouter>
);
};
export default App;
Création de la page de destination
La page de destination dans notre cas est la seule page disponible pour un utilisateur non authentifié. Il contiendra des liens vers les pages d’inscription et de connexion. Il ressemblera à ceci:
import React from "react";
import { Link } from "react-router-dom";
const Landing = () => {
return (
<>
<header style={{ textAlign: "center" }}>
<h1>Welcome to my world</h1>
</header>
<main style={{ display: "flex", justifyContent: "center", gap: "2rem" }}>
<Link
to="/signup"
style={{
textDecoration: "none",
border: "1px solid gray",
padding: "0.5rem 1rem",
backgroundColor: "wheat",
color: "#333",
}}
>
Sign Up
</Link>
<Link
to="/login"
style={{
textDecoration: "none",
border: "1px solid gray",
padding: "0.5rem 1rem",
backgroundColor: "whitesmoke",
color: "#333",
}}
>
Login
</Link>
</main>
</>
);
};
export default Landing;
Décomposons-le :
- Le composant renvoie un élément de fragment React représenté par une balise vide.
- Le fragment contient deux éléments :
<header>
et<main>
. L’en-tête renvoie un<h1>
et y centre le texte, tandis que l’élément principal renvoie deux liens à partir dereact-router-dom
et les centre également. - Une couleur d’arrière-plan différente est fournie pour les deux liens afin d’améliorer l’expérience utilisateur.
Ensuite, nous pouvons ouvrir le screens/index.js
fichier et exporter le Landing.jsx
ainsi:
export { default as Landing } from "./Landing";
Après cela, nous pouvons l’importer dans le App.js
fichier, où nous configurons une route pour celui-ci :
import { Landing } from "./screens";
Aussi:
<Route
path="https://www.sitepoint.com/"
element={user?.email ? <Navigate to="/home" /> : <Landing />}
/>
Création d’un hook useFetch
UN accrocher dans React est un type spécial de fonction qui vous permet d’utiliser les fonctionnalités de React. Pour créer un crochet, ouvrez hooks/useFetch.jsx
et ajoutez le code suivant :
import { useState } from "react";
const useFetch = (url) => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const handleGoogle = async (response) => {
console.log(response)
};
return { loading, error, handleGoogle };
};
export default useFetch;
Création d’une page d’inscription
Ouvrez le screens/Signup.jsx
fichier et ajoutez le code suivant :
import React, { useEffect } from "react";
import { Link } from "react-router-dom";
import useFetch from "../hooks/useFetch";
const SignUp = () => {
const { handleGoogle, loading, error } = useFetch(
"http://localhost:5152/signup"
);
useEffect(() => {
if (window.google) {
google.accounts.id.initialize({
client_id: process.env.REACT_APP_GOOGLE_CLIENT_ID,
callback: handleGoogle,
});
google.accounts.id.renderButton(document.getElementById("signUpDiv"), {
theme: "filled_black",
text: "continue_with",
shape: "pill",
});
}
}, [handleGoogle]);
return (
<>
<nav style={{ padding: "2rem" }}>
<Link to="https://www.sitepoint.com/">Go Back</Link>
</nav>
<header style={{ textAlign: "center" }}>
<h1>Register to continue</h1>
</header>
<main
style={{
display: "flex",
justifyContent: "center",
flexDirection: "column",
alignItems: "center",
}}
>
{error && <p style={{ color: "red" }}>{error}</p>}
{loading ? (
<div>Loading....</div>
) : (
<div id="signUpDiv" data-text="signup_with"></div>
)}
</main>
<footer></footer>
</>
);
};
export default SignUp;
Décomposons-le :
- Nous extrayons les états et les fonctions disponibles de la
useFetch
accrocher. Nous transmettons également l’URL que nous appellerons pour gérer notre connexion au serveur. - Dans
useEffect
nous vérifions la disponibilité du script de Google — géré par le script que nous avons mis dans lepublic.index.html
dossier. - On utilise alors le
initialize
disponible dans le script pour gérer la fonctionnalité du bouton d’authentification. - Nous passons également une fonction de rappel, que nous avons déjà définie dans le
useFetch
accrocher.
Ensuite, nous utiliserons le renderButton
méthode pour afficher notre bouton d’authentification à l’écran. Le premier paramètre que nous passons est l’élément dans lequel le bouton sera intégré, en utilisant le getElementById
méthode. Les paramètres suivants que nous pouvons passer sont utilisés pour personnaliser l’apparence du bouton. Il a le paramètre requis suivant :
type
: ceci accepte deux valeurs — standard et icône.
De plus, il a des paramètres facultatifs, notamment les suivants :
theme
: le thème du bouton. Il peut accepter l’un des éléments suivants :filled_blue
,outline
etfilled_black
.size
: définit la taille du bouton. Il acceptelarge
,medium
etsmall
.text
: définit le texte du bouton. Il accepte l’un des éléments suivants :signin_with
,signup_with
,continue_with
etsignin
.shape
: définit la forme du bouton. Il accepterectangular
,pill
,circle
ousquare
.logo_alignment
: définit comment le logo sera placé dans le bouton. Il peut accepterleft
oucenter
.width
: définit la largeur du bouton. Il convient de noter que la largeur maximale est de 400.
Une autre option est locale
qui est utilisé pour définir une langue spécifique.
Nous vérifions également la disponibilité d’une erreur et l’affichons à l’utilisateur. Nous vérifions également l’état de chargement.
Création de la page de connexion
La page de connexion est similaire à la page d’inscription. La seule différence est l’URL du serveur et le texte du bouton. Le code devrait ressembler à ceci :
import React, { useEffect } from "react";
import { Link } from "react-router-dom";
import useFetch from "../hooks/useFetch";
const Login = () => {
const { handleGoogle, loading, error } = useFetch(
"http://localhost:5152/login"
);
useEffect(() => {
if (window.google) {
google.accounts.id.initialize({
client_id: process.env.REACT_APP_GOOGLE_CLIENT_ID,
callback: handleGoogle,
});
google.accounts.id.renderButton(document.getElementById("loginDiv"), {
theme: "filled_black",
text: "signin_with",
shape: "pill",
});
}
}, [handleGoogle]);
return (
<>
<nav style={{ padding: "2rem" }}>
<Link to="https://www.sitepoint.com/">Go Back</Link>
</nav>
<header style={{ textAlign: "center" }}>
<h1>Login to continue</h1>
</header>
<main
style={{
display: "flex",
justifyContent: "center",
flexDirection: "column",
alignItems: "center",
}}
>
{error && <p style={{ color: "red" }}>{error}</p>}
{loading ? <div>Loading....</div> : <div id="loginDiv"></div>}
</main>
<footer></footer>
</>
);
};
export default Login;
Noter la google.accounts.id.prompt()
est utilisé pour demander automatiquement à l’utilisateur de se connecter dès qu’il ouvre votre page Web. Il peut être placé dans le fichier racine ou la page de connexion.
Créez également un .env.local
fichier dans le dossier racine et ajoutez ce qui suit :
REACT_APP_GOOGLE_CLIENT_ID=your client id
Ensuite, nous exportons la page d’inscription et de connexion à partir du screens.index.js
dossier:
export { default as Login } from "./Login";
export { default as Signup } from "./SignUp";
Après cela, nous configurons leurs routes dans le App.js
dossier:
import { Landing, Login, Signup } from "./screens";
Aussi:
<Route
path="/signup"
element={user?.email ? <Navigate to="/home" /> : <Signup />}
/>
<Route
path="/login"
element={user?.email ? <Navigate to="/home" /> : <Login />}
/>
Mise à jour de useFetch
L’authentification Google renvoie une réponse avec les informations d’identification JWT. Cependant, pour vérifier son authenticité et également créer une session pour l’utilisateur, nous ferons des appels ultérieurs au serveur. Nous devrions mettre à jour notre hooks/useFetch
fichier ressemble à ceci :
const handleGoogle = async (response) => {
setLoading(true);
fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ credential: response.credential }),
})
.then((res) => {
setLoading(false);
return res.json();
})
.then((data) => {
if (data?.user) {
localStorage.setItem("user", JSON.stringify(data?.user));
window.location.reload();
}
throw new Error(data?.message || data);
})
.catch((error) => {
setError(error?.message);
});
};
Décomposons cela :
- Notre fonction de rappel accepte un paramètre de l’authentification Google transmis en réponse.
- On utilise alors
fetch
pour faire une requête au serveur. - Lorsque nous obtenons la réponse appropriée, nous stockons l’utilisateur dans le
localStorage
au format JSON.
Création de routes d’inscription et de connexion
Ouvrez le server.js
dossier. Tout d’abord, nous allons créer une fonction qui vérifie les informations d’identification que nous recevrons :
const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID;
const client = new OAuth2Client(GOOGLE_CLIENT_ID);
async function verifyGoogleToken(token) {
try {
const ticket = await client.verifyIdToken({
idToken: token,
audience: GOOGLE_CLIENT_ID,
});
return { payload: ticket.getPayload() };
} catch (error) {
return { error: "Invalid user detected. Please try again" };
}
}
Créer un .env
fichier dans le dossier racine du serveur et ajoutez ce qui suit :
# .env
GOOGLE_CLIENT_ID=your client id
JWT_SECRET=mySecret
Ensuite, créez la route d’inscription :
app.post("/signup", async (req, res) => {
try {
if (req.body.credential) {
const verificationResponse = await verifyGoogleToken(req.body.credential);
if (verificationResponse.error) {
return res.status(400).json({
message: verificationResponse.error,
});
}
const profile = verificationResponse?.payload;
DB.push(profile);
res.status(201).json({
message: "Signup was successful",
user: {
firstName: profile?.given_name,
lastName: profile?.family_name,
picture: profile?.picture,
email: profile?.email,
token: jwt.sign({ email: profile?.email }, "myScret", {
expiresIn: "1d",
}),
},
});
}
} catch (error) {
res.status(500).json({
message: "An error occurred. Registration failed.",
});
}
});
Créez également la route de connexion :
app.post("/login", async (req, res) => {
try {
if (req.body.credential) {
const verificationResponse = await verifyGoogleToken(req.body.credential);
if (verificationResponse.error) {
return res.status(400).json({
message: verificationResponse.error,
});
}
const profile = verificationResponse?.payload;
const existsInDB = DB.find((person) => person?.email === profile?.email);
if (!existsInDB) {
return res.status(400).json({
message: "You are not registered. Please sign up",
});
}
res.status(201).json({
message: "Login was successful",
user: {
firstName: profile?.given_name,
lastName: profile?.family_name,
picture: profile?.picture,
email: profile?.email,
token: jwt.sign({ email: profile?.email }, process.env.JWT_SECRET, {
expiresIn: "1d",
}),
},
});
}
} catch (error) {
res.status(500).json({
message: error?.message || error,
});
}
});
Décomposons-le :
- Dans les routes, nous vérifions d’abord que les informations d’identification sont passées dans le corps. Nous essayons ensuite de vérifier les informations d’identification. S’il y a une erreur, nous la renvoyons au client au format JSON.
- Dans la route d’inscription, nous stockons les profils des utilisateurs dans le tableau DB et envoyons une réponse de réussite avec un e-mail signé JWT en tant que jeton.
- Dans la route de connexion, nous vérifions si l’utilisateur existe dans la base de données et si ce n’est pas le cas, renvoyons une erreur. S’il existe, nous envoyons également une réponse de réussite avec un e-mail signé JWT sous forme de jeton avec d’autres paramètres.
Mise à jour d’App.js
Dans le App.js
de l’application cliente, nous mettrons à jour le fichier pour rechercher un utilisateur dans local storage
avec le code suivant :
useEffect(() => {
const theUser = localStorage.getItem("user");
if (theUser && !theUser.includes("undefined")) {
setUser(JSON.parse(theUser));
}
}, []);
Création de Home.jsx
La Home.jsx
file est la page qui sera disponible pour l’utilisateur après une inscription ou une connexion réussie :
import React from "react";
const Home = ({ user }) => {
const logout = () => {
localStorage.removeItem("user");
window.location.reload();
};
return (
<div style={{ textAlign: "center", margin: "3rem" }}>
<h1>Dear {user?.email}</h1>
<p>
You are viewing this page because you are logged in or you just signed
up
</p>
<div>
<button
onClick={logout}
style={{
color: "red",
border: "1px solid gray",
backgroundColor: "white",
padding: "0.5rem 1rem",
cursor: "pointer",
}}
>
Logout
</button>
</div>
</div>
);
};
export default Home;
Ensuite, nous allons l’exporter depuis le screens/index.js
fichier comme ceci:
export { default as Home } from "./Home";
Après cela, nous importerons et configurerons son itinéraire dans App.js
:
import { Home, Landing, Login, Signup } from "./screens";
Aussi:
<Route
path="/home"
element={user?.email ? <Home user={user} /> : <Navigate to="https://www.sitepoint.com/" />}
/>
Conclusion
Toutes nos félicitations! Nous avons configuré la nouvelle authentification Google.
Encore une fois, le code source est disponible ici : Serveur et Client.
Lecture connexe :
Source link