Fermer

octobre 23, 2022

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

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.

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.

Ajouter un nouveau projet

Étape 3

Ajoutez un nom de projet. J’ai choisi connect-google-auth-article.

Ajouter le nom du projet

Étape 4

Cliquez sur le menu déroulant à l’étape 1 pour sélectionner le projet.

Sélectionnez un projet

Étape 5

L’écran suivant que vous voyez devrait ressembler à l’exemple ci-dessous. Cliquez ensuite sur le tableau de bord.

Pré 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 ».

Pré-activer

Étape 7

Sélectionnez le type de consentement souhaité. J’ai choisi externe et appuyé CRÉER.

concentré

É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.

Type d'application, application Web ;  Nom, connect-google-auth-article ;  URI1, http://localhost ;  URI2, http://localhost:3000 ;

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.

serment

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 de react-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 useEffectnous vérifions la disponibilité du script de Google — géré par le script que nous avons mis dans le public.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, outlineet filled_black.
  • size: définit la taille du bouton. Il accepte large, mediumet small.
  • text: définit le texte du bouton. Il accepte l’un des éléments suivants : signin_with, signup_with, continue_withet signin.
  • shape: définit la forme du bouton. Il accepte rectangular, pill, circleou square.
  • logo_alignment: définit comment le logo sera placé dans le bouton. Il peut accepter left ou center.
  • width: définit la largeur du bouton. Il convient de noter que la largeur maximale est de 400.

Une autre option est localequi 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