Rutas privadas

Permitir o denegar el acceso en función de si el usuario está autentificado

Esta parte con Auth0 ya viene de serie ( función withAuthenticationRequired). Si usas firebase, debes programarla.

Para las rutas de índole privada, utilizaré un enrutamiento ligeramente diferente del habitual.

routes.js

<Route exact path="/" element={<PrivateRoute component={Page1} />} />

En el componente PrivateRoute evalúo si el usuario está autentificado. Si lo está devuelvo el componente que toque.

PrivateRoute.js

import { useAuth } from '../hooks/use-auth';

const PrivateRoute = ({ component: Component }) => {
    const { isAuthenticated } = useAuth();
    return isAuthenticated && <Component />;
};

export default PrivateRoute;

El state contendrá una propiedad user con los datos del usuario que se ha logueado. Hemos tenido que alimentar previamente el state con estos datos. La propiedad isAuthenticated valdrá true, siempre que la propiedad user no sea null (La doble admiración hace una transformación a booleano de lo que le pongas a la derecha, de tal forma que si es null o undefined, devolverá false).

use-auth.js

import { useContext } from "react";

export const useAuth = () => {
    const [state, setState] = useContext(AppContext);

    return {
        isAuthenticated: !!state.user,
    };
}

Recuperar datos del usuario logueado del servidor (explicación para auth0)

Cada vez que cambie el estado del usuario, llamaremos a la función onAuthChange que se encargará de recuperar sus datos correspondientes y guardarlos en el context API.

routes.js

import { useEffect } from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { withAuthenticationRequired } from "@auth0/auth0-react";
import PrivateRoute from './PrivateRoute';
import { useAuth } from '../hooks/use-auth';
import Page1 from '../../pages/page1';
import Page2 from '../../pages/page2';

const R = () => {
    const { onAuthChange, isAuthenticated } = useAuth();
    useEffect(() => {
        onAuthChange();
    }, [isAuthenticated]);
    return (
        <BrowserRouter basename={process.env.PUBLIC_PATH}>
            <Routes>
                <Route exact path="/" element={<PrivateRoute component={Page1} />} />
                <Route exact path="/page2" element={<PrivateRoute component={Page2} />} />
                <Route path="*" component={() => <div>404</div>} />
            </Routes>
        </BrowserRouter>
    )
};

export default withAuthenticationRequired(R);

En el caso de que todavía no tengamos los datos del usuario almacenados en la contextAPI ( !state.user), recuperaremos sus datos.

El método getIdTokenClaims, de auth0, recupera un token que identifica al usuario. Este token, fundamentalmente contiene el id y correo del usuario. Estos datos estarán cifrados y serán enviados a nuestro servidor (en nuestro caso, mediante la función startLogin).

En nuestro servidor, volveremos a usar funciones de auth0 para:

  1. Validar que el token enviado es correcto.
  2. Extraer los datos necesarios (id, correo, etc.) que nos permitan recuperar la información del usuario logueado.

use-auth.js

import { useContext } from "react";
import { useAuth0 } from "@auth0/auth0-react";
import { startLogin } from "../services/api";
import { AppContext } from '../provider';

export const useAuth = () => {
    const { getIdTokenClaims, logout, isAuthenticated } = useAuth0();
    const [state, setState] = useContext(AppContext);

    const onAuthChange = () => {
        if (isAuthenticated) {
            getIdTokenClaims().then(async ({ __raw: idToken }) => {
                const u = await startLogin(idToken);
                setState({ ...state, user: u.user });
            });
        }
    };

    const logoutUser = () => {
        logout();
        setState({ ...state, user: null});
    }

    return {
        logoutUser,
        onAuthChange,
        isAuthenticated,
    };
}
← Compilar (build o publicar) una aplicación de React
Testing →