web-dev-qa-db-fra.com

Empêcher le routage dans React lorsque l'utilisateur modifie manuellement l'URL dans l'onglet du navigateur

Je suis coincé dans un problème qui se produit lorsque l'utilisateur modifie manuellement l'itinéraire dans l'onglet du navigateur et appuie sur Entrée. Cela oblige mon routeur de réaction à naviguer vers l'état entré par l'utilisateur. Je souhaite empêcher cela et autoriser le routage uniquement via le flux que j'ai mis en œuvre par des clics sur les boutons de mon site Web.

Certains de mes écrans ont besoin de données qui ne seront disponibles que si l'utilisateur navigue sur le site en utilisant le flux attendu. Si l'utilisateur essaie directement de naviguer vers un itinéraire particulier en modifiant manuellement l'itinéraire dans l'URL, il peut ignorer le flux souhaité et, par conséquent, l'application s'arrêtera.

Autre scénario, au cas où je souhaiterais empêcher certains utilisateurs d'accéder à certaines routes, mais l'utilisateur connaît le chemin d'accès et le saisit manuellement dans l'URL du navigateur, puis cet écran lui sera présenté mais ne devrait pas l'être.

17
Vishal Gulati

Ce que je fais est d'utiliser un accessoire de la page précédente, si cet accessoire n'est pas défini (ce qui signifie que l'utilisateur n'a pas suivi la procédure régulière :) hehe) Je renvoie simplement l'utilisateur à la page de destination ou ailleurs.

2
Chigo Kawa

Vous pouvez créer un garde-route à l'aide de HOC. Par exemple, vous ne voulez pas qu'un utilisateur non autorisé passe la route /profile, vous pouvez alors effectuer les opérations suivantes:

// requireAuthorized.js (HOC)
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import {Redirect} from 'react-router-dom'

const connector = connect(
  state => ({
    isAuthorized: state.profile !== null // say, you keep user profile in redux
  })
)

export default (WrappedComponent) => {
  return (
    connector(
      class extends Component {
        static propTypes = {
          isAuthorized: PropTypes.bool.isRequired
        }

        render () {
          const {isAuthorized, ...clearedProps} = this.props
          if (isAuthorized) {
            return <WrappedComponent {...clearedProps} />
          } else {
            return <Redirect to={{pathname: '/login'}} />
          }
        }
      }
    )
  )
}


// ProfilePage.jsx
import React from 'react'
...
import requireAdmin from '../hocs/requireAdmin' // adjust path

class ProfilePage extends React.Component {
  ...
  render () {
    return (
      <div>
        ...
      </div>
    )
  }
}

export default requireAdmin(ProfilePage)

Faites attention à la déclaration d'exportation dans mon ProfilePage.js

2
GProst

Quelque chose comme ça convient. Vous créez HOC Route avec une fonction de bouclage qui traite des accessoires d'authentification/de contexte. Remarque: cela concerne l'accès direct à l'itinéraire, pas aux éléments de menu et autres. Cela doit être traité de manière similaire sur les composants menu/menuItem.

import requireAuth from "../components/login/requireAuth";

class Routes extends React.Component<RoutesProps, {}> {
    render() {
        return (
            <div>
                <Switch>
                    <Route exact={true} path="/" component={requireAuth(Persons, ["UC52_003"])} />
                    <Route path="/jobs" component={requireAuth(Jobs, ["UC52_006"])} />
                </Switch>
            </div>
        )
    }
}


export default function (ComposedComponent, privileges) {

    interface AuthenticateProps {
        isAuthenticated: boolean
        userPrivileges: string[]
    }
    class Authenticate extends React.Component<AuthenticateProps, {}> {
        constructor(props: AuthenticateProps) {
            super(props)
        }

        render() {
            return (
                isAuthorized(this.props.isAuthenticated, privileges, this.props.userPrivileges) &&
                <ComposedComponent {...this.props} /> || <div>User is not authorised to access this page.</div>
            );
        }
    }

    function mapStateToProps(state) {
        return {
            isAuthenticated: state.userContext ? state.userContext.isAuthenticated : false,
            userPrivileges: state.userContext ? state.userContext.user ? state.userContext.user.rights : [] : []
        };
    }

    return connect(mapStateToProps, null)(Authenticate);
}
1
jan

Je suggère d'utiliser cette bibliothèque pour la solution la plus propre (ou au moins d'en faire une implémentation personnelle similaire).

Ensuite, vous créez un contrôle d'authentification HOC:

export const withAuth = connectedReduxRedirect({
    redirectPath: '/login',
    authenticatedSelector: state => state.user.isAuthenticated, // or whatever you use
    authenticatingSelector: state => state.user.loading,
    wrapperDisplayName: 'UserIsAuthenticated'
});

Et vous pouvez facilement créer un flux HOC:

export const withFlow = (step) = connectedReduxRedirect({
    redirectPath: '/initial-flow-step',
    authenticatedSelector: state => state.flow[step] === true,
    wrapperDisplayName: 'FlowComponent'
});

Ensuite, initialisez votre composant

const AuthenticatedComponent = withAuth(Dashboard)
const SecondStepComponent = withFlow("first-step-finished")(SecondStep)
const ThirdStepComponent = withFlow("second-step-finished")(ThirdStep)

Vous pouvez facilement créer une étape de flux authentifié en composant HOC:

const AuthSecondStepComponent = withAuth(withFlow("first-step-finished")(SecondStep))

La seule chose qui est importante est que vous mettez à jour votre état redux correctement en passant par votre flux d'étapes. Lorsque l'utilisateur termine la première étape, vous définissez

state.flow["first-step-finished"] = true // or however you manage your state

de sorte que lorsque l'utilisateur navigue manuellement vers une page spécifique, il n'a pas cet état redux car il s'agit d'un état en mémoire et est redirigé vers la route redirectPath.

0
zhuber