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.
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.
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
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);
}
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
.