Jak zacházet s ověřenými cestami pomocí Next.js

Jak vytvořit HOC (komponenta vyššího řádu), která může podmíněně přesměrovat uživatele na základě jeho stavu přihlášeného nebo odhlášeného.

V Next.js jsou ve výchozím nastavení všechny vaše trasy zpracovány stejně.

I když vaše konkrétní aplikace může obsahovat stránky nebo trasy, které jsou určeny pouze pro přihlášené uživatele, Next.js po vybalení není poskytují způsob, jak izolovat tyto stránky na základě stavu ověření uživatele.

To se očekává, protože Next.js je navržen tak, aby zvládl jednoduchou, dobře definovanou sadu úkolů. Zatímco může být použit jako front-end pro aplikaci – jako v základním vzoru Next.js CheatCode – tradičně se používá ke generování statických marketingových webů nebo webů podporovaných bezhlavým CMS.

Naštěstí řešení tohoto problému není příliš složité. Abychom to vyřešili, implementujeme dvě komponenty:

  1. authenticatedRoute což bude funkce, která vrátí komponentu React zabalenou s podmíněnou kontrolou stavu autentizace uživatele a přesměrováním, pokud je uživatel nedostupný.
  2. publicRoute což bude funkce, která vrátí komponentu React zabalenou s podmíněnou kontrolou stavu autentizace uživatele a přesměrováním, pokud je uživatel přítomen.

Implementace komponenty Authenticated Route

Nejprve sestavíme kostru našeho HOC a prodiskutujeme, jak bude fungovat:

/components/AuthenticatedRoute/index.js

import React from "react";

const authenticatedRoute = (Component = null, options = {}) => {
 // We'll handle wrapping the component here.
};

export default authenticatedRoute;

Zde exportujeme jednoduchou JavaScriptovou funkci, která má dva argumenty:React Component jako první argument a objekt options jako druhý. Component představuje součást chráněné stránky, kterou chceme podmíněně vykreslit.

Když to začneme používat, uděláme něco takového:

/pages//index.js

import authenticatedRoute from '../../components/AuthenticatedRoute';

const MyComponent = () => {
  [...]
};

export default authenticatedRoute(MyComponent, { pathAfterFailure: '/login' })

Pojďme kupředu, pojďme naplnit naše HOC komponentou jádra:

/components/AuthenticatedRoute/index.js

import React from "react";

const authenticatedRoute = (Component = null, options = {}) => {
  class AuthenticatedRoute extends React.Component {
    state = {
      loading: true,
    };

    render() {
      const { loading } = this.state;

      if (loading) {
        return <div />;
      }

      return <Component {...this.props} />;
    }
  }

  return AuthenticatedRoute;
};

export default authenticatedRoute;

Zde jsme naplnili naše authenticatedRoute tělo funkce s komponentou React založenou na třídě. Myšlenka je taková, že chceme využít stav a – dále – componentDidMount funkce pro třídu, abychom se mohli rozhodnout, zda chceme vykreslit předané Component , nebo z něj přesměrovat uživatele.

/components/AuthenticatedRoute/index.js


import React from "react";
import Router from "next/router";

const authenticatedRoute = (Component = null, options = {}) => {
  class AuthenticatedRoute extends React.Component {
    state = {
      loading: true,
    };

    componentDidMount() {
      if (this.props.isLoggedIn) {
        this.setState({ loading: false });
      } else {
        Router.push(options.pathAfterFailure || "/login");
      }
    }

    render() {
      const { loading } = this.state;

      if (loading) {
        return <div />;
      }

      return <Component {...this.props} />;
    }
  }

  return AuthenticatedRoute;
};

export default authenticatedRoute;

Nyní s naším componentDidMount přidáno, vidíme implementované naše základní chování. Uvnitř chceme vědět jen to, zda existuje nějaký přihlášený uživatel nebo ne? Pokud existuje přihlášeného uživatele, chceme říci „pokračujte a vykreslete předané Component ." Můžeme vidět, že se to odehrává dole v render() metoda AuthenticatedRoute komponenta.

Zde říkáme, pokud loading je true , stačí vrátit prázdné <div /> (nebo uživateli nic neukazovat). Pokud nejsme načítání, stačí spustit return ve spodní části render() .

Dosáhneme toho, že „dokud nebudeme vědět, že máme přihlášeného uživatele, nezobrazovat nic, a pokud uděláme mít přihlášeného uživatele, ukažte mu stránku, na kterou se snaží vstoupit."

Zpět v componentDidMount() v else prohlášení, říkáme "dobře, nevypadá to, že je uživatel přihlášen, takže ho přesměrujeme." K provedení přesměrování v tomto příkladu používáme vestavěný router Next.js, který provede přesměrování za nás, ale můžete použít jakýkoli router JavaScript nebo React, který byste chtěli (např. pokud bychom používali React Router 'd udělat this.props.history.push(options.pathAfterFailure || '/login') .

Dávat smysl? Pokud tedy máme uživatele, ukažte mu komponentu. Pokud uživatele nemáme, přesměrujte ho na jinou trasu.

Určení stavu přihlášení

Technicky vzato, to je vše, co musíme udělat. Možná se ale ptáte "jak poznáme, že je uživatel přihlášen?" Zde přichází na řadu vaše vlastní aplikace. V tomto příkladu používáme CheatCode Next.js Boilerplate, který spoléhá na přítomnost ověřeného uživatele (pokud je k dispozici) v globálním obchodě Redux.

Aby to všechno bylo trochu konkrétnější, podívejme se nyní na toto nastavení:

/components/AuthenticatedRoute/index.js

import React from "react";
import Router from "next/router";
import { connect } from "react-redux";

const authenticatedRoute = (Component = null, options = {}) => {
  class AuthenticatedRoute extends React.Component {
    state = {
      loading: true,
    };

    componentDidMount() {
      if (this.props.isLoggedIn) {
        this.setState({ loading: false });
      } else {
        Router.push(options.pathAfterFailure || "/login");
      }
    }

    render() {
      const { loading } = this.state;

      if (loading) {
        return <div />;
      }

      return <Component {...this.props} />;
    }
  }

  return connect((state) => ({
    isLoggedIn: state?.authenticated && !!state?.user,
  }))(AuthenticatedRoute);
};

export default authenticatedRoute;

Velkou změnou, kterou jsme zde provedli, je import connect() metoda z react-redux balíček (již nainstalovaný ve standardu) a poté zavolejte tuto funkci a předejte jí mapStateToProps funkci a poté ji obalíme kolem naší komponenty. Aby bylo jasno, tato část:

/components/AuthenticatedRoute/index.js

return connect((state) => ({
  isLoggedIn: state?.authenticated && !!state?.user,
}))(AuthenticatedRoute);

Zde je funkce, kterou předáme jako první argument do connect() je mapStateToProps funkce (jak je pojmenována v react-redux dokumentace). Tato funkce převezme aktuální globální stav pro aplikaci poskytovanou <ReduxProvider /> v /pages/_app.js ve standardu CheatCode Next.js.

Pomocí tohoto stavu, jak název napovídá, se mapuje tento stav na podporu komponenty React, která bude předána našemu <AuthenticatedRoute /> komponenta definovaná těsně nad ním.

Když se podíváme zblízka, zde nastavujeme podpěru s názvem isLoggedIn , zkontrolujte, zda authenticated hodnota na našem stavu je true a zda máme či nemáme user objekt na stát. Pokud ano? Uživatel je přihlášen! Pokud ne, isLoggedIn je nepravdivé.

Pokud se podíváte zpět do componentDidMount() Zde vkládáme nový isLoggedIn rekvizita k použití.

Použití jiných zdrojů ověřování

Pokud ne pomocí CheatCode Next.js Boilerplate, jak se dostanete do ověřeného stavu vašeho uživatele, závisí na vaší aplikaci. Rychlý a špinavý příklad použití jiného API by vypadal asi takto:

import React from "react";
import Router from "next/router";
import { connect } from "react-redux";
import { myAuthenticationAPI } from 'my-authentication-api';

const authenticatedRoute = (Component = null, options = {}) => {
  class AuthenticatedRoute extends React.Component {
    state = {
      loading: true,
    };

    async componentDidMount() {
      const isLoggedIn = await myAuthenticationAPI.isLoggedIn();

      if (isLoggedIn) {
        this.setState({ loading: false });
      } else {
        Router.push(options.pathAfterFailure || "/login");
      }
    }

    render() {
      const { loading } = this.state;

      if (loading) {
        return <div />;
      }

      return <Component {...this.props} />;
    }
  }

  return AuthenticatedRoute;
};

export default authenticatedRoute;

V tomto příkladu je téměř vše identické, ale namísto předvídání ověřovací hodnoty pocházející z obchodu Redux zavoláme přímo naše autentizační API (např. Firebase), přičemž se spoléháme na návratovou hodnotu tohoto volání jako naše isLoggedIn stav.

Implementujte komponentu Public Route

Nyní několik dobrých zpráv:naše publicRoute komponenta je identická k tomu, na co jsme se podívali výše, s jednou malou změnou:

/components/PublicRoute/index.js

import React from "react";
import Router from "next/router";
import { connect } from "react-redux";

const publicRoute = (Component = null, options = {}) => {
  class PublicRoute extends React.Component {
    state = {
      loading: true,
    };

    componentDidMount() {
      if (!this.props.isLoggedIn) {
        this.setState({ loading: false });
      } else {
        Router.push(options.pathAfterFailure || "/documents");
      }
    }

    render() {
      const { loading } = this.state;

      if (loading) {
        return <div />;
      }

      return <Component {...this.props} />;
    }
  }

  return connect((state) => ({
    isLoggedIn: state?.authenticated && !!state?.user,
  }))(PublicRoute);
};

export default publicRoute;

Dokážeš to zjistit? Nahoře v componentDidMount přidali jsme ! říct „pokud uživatel není přihlášeni, pokračujte a vykreslete komponentu. Pokud jsou přihlášeni, přesměrujte je."

Doslova inverzní logika k našemu authenticatedRoute . bod zde je, že chceme použít publicRoute() komponentu na trasách jako /login nebo /signup k přesměrování již ověřených uživatelů pryč z těch stránek. To zajišťuje, že později nedojde k nepořádkům v databázi, jako jsou duplicitní uživatelé nebo vícenásobné uživatelské relace.

Zabalení

V tomto tutoriálu jsme se naučili jednoduchý vzor pro vytvoření HOC (komponenta vyššího řádu) pro přesměrování uživatelů v naší aplikaci na základě jejich stavu přihlášení (ověřování). Naučili jsme se, jak implementovat základní komponentu, která se „obtéká“ kolem komponenty, kterou se snažíme chránit, a jak implementovat základní logiku pro zpracování procesu vykreslování a přesměrování.

Podívali jsme se také na příklady použití skutečných ověřovacích dat, abychom přidali kontext a objasnili, jak může tento vzor fungovat v jakémkoli nastavení ověřování v Next.js.


No