(Utilisation de Redux pour la gestion de l'état)
Si l'utilisateur essaie d'accéder à une url, je vais d'abord vérifier si le jeton d'accès est disponible, sinon je redirige vers la page de connexion, Une fois que l'utilisateur se connecte en utilisant la page de connexion, nous stockons cela dans le localstorage ainsi que dans notre état redux. (localstorage ou cookies..nous gardons ce sujet hors du contexte pour le moment).
puisque l'état de redux a été mis à jour et que les routes privées seront redirigées. maintenant nous avons un jeton d'accès et nous allons rediriger vers la page d'accueil.
Stockez les données décodées de la charge utile de l'autorisation également dans l'état redux et passez-les au contexte react. (Nous n'avons pas besoin d'utiliser le contexte mais pour accéder à l'autorisation dans n'importe lequel de nos composants enfants imbriqués, il est plus facile d'y accéder à partir du contexte plutôt que de connecter chaque composant enfant à redux)
Toutes les routes qui n'ont pas besoin de rôles spéciaux peuvent être accédées directement après la connexion S'il a besoin d'un rôle comme admin (nous avons fait une route protégée qui vérifie s'il a le rôle désiré, sinon il est redirigé vers un composant non autorisé).
de la même manière dans n'importe quel composant si vous devez désactiver un bouton ou quelque chose en fonction du rôle.
simplement vous pouvez faire de cette manière
const authorization = useContext(AuthContext);
const [hasAdminRole] = checkAuth({authorization, roleType:"admin"});
const [hasLeadRole] = checkAuth({authorization, roleType:"lead"});
<Button disable={!hasAdminRole} />Admin can access</Button>
<Button disable={!hasLeadRole || !hasAdminRole} />admin or lead can access</Button>
Et si l'utilisateur essaie d'insérer un jeton factice dans le stockage local ? Comme nous avons un jeton d'accès, nous allons rediriger vers le composant d'accueil. Mon composant d'accueil fera un appel au repos pour récupérer les données, puisque le jeton jwt était factice, l'appel au repos retournera un utilisateur non autorisé. Je fais donc un appel à la déconnexion (qui effacera le stockage local et redirigera à nouveau vers la page de connexion). Si la page d'accueil contient des données statiques et ne fait pas d'appel api (alors vous devriez avoir un appel api de vérification de jeton dans le backend afin de pouvoir vérifier si le jeton est RÉEL avant de charger la page d'accueil).
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, Switch } from 'react-router-dom';
import history from './utils/history';
import Store from './statemanagement/store/configureStore';
import Privateroutes from './Privateroutes';
import Logout from './components/auth/Logout';
ReactDOM.render(
<Store>
<Router history={history}>
<Switch>
<Route path="/logout" exact component={Logout} />
<Route path="/" exact component={Privateroutes} />
<Route path="/:someParam" component={Privateroutes} />
</Switch>
</Router>
</Store>,
document.querySelector('#root')
);
Histoire.js
import { createBrowserHistory as history } from 'history';
export default history({});
Privateroutes.js
import React, { Fragment, useContext } from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import { AuthContext, checkAuth } from './checkAuth';
import App from './components/App';
import Home from './components/home';
import Admin from './components/admin';
import Login from './components/auth/Login';
import Unauthorized from './components/Unauthorized ';
import Notfound from './components/404';
const ProtectedRoute = ({ component: Component, roleType, ...rest })=> {
const authorization = useContext(AuthContext);
const [hasRequiredRole] = checkAuth({authorization, roleType});
return (
<Route
{...rest}
render={props => hasRequiredRole ?
<Component {...props} /> :
<Unauthorized {...props} /> }
/>)};
const Privateroutes = props => {
const { accessToken, authorization } = props.authData;
if (accessToken) {
return (
<Fragment>
<AuthContext.Provider value={authorization}>
<App>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/login" render={() => <Redirect to="/" />} />
<Route exact path="/home" component={Home} />
<ProtectedRoute
exact
path="/admin"
component={Admin}
roleType="admin"
/>
<Route path="/404" component={Notfound} />
<Route path="*" render={() => <Redirect to="/404" />} />
</Switch>
</App>
</AuthContext.Provider>
</Fragment>
);
} else {
return (
<Fragment>
<Route exact path="/login" component={Login} />
<Route exact path="*" render={() => <Redirect to="/login" />} />
</Fragment>
);
}
};
// my user reducer sample
// const accessToken = localStorage.getItem('token')
// ? JSON.parse(localStorage.getItem('token')).accessToken
// : false;
// const initialState = {
// accessToken: accessToken ? accessToken : null,
// authorization: accessToken
// ? jwtDecode(JSON.parse(localStorage.getItem('token')).accessToken)
// .authorization
// : null
// };
// export default function(state = initialState, action) {
// switch (action.type) {
// case actionTypes.FETCH_LOGIN_SUCCESS:
// let token = {
// accessToken: action.payload.token
// };
// localStorage.setItem('token', JSON.stringify(token))
// return {
// ...state,
// accessToken: action.payload.token,
// authorization: jwtDecode(action.payload.token).authorization
// };
// default:
// return state;
// }
// }
const mapStateToProps = state => {
const { authData } = state.user;
return {
authData: authData
};
};
export default connect(mapStateToProps)(Privateroutes);
checkAuth.js
import React from 'react';
export const AuthContext = React.createContext();
export const checkAuth = ({ authorization, roleType }) => {
let hasRequiredRole = false;
if (authorization.roles ) {
let roles = authorization.roles.map(item =>
item.toLowerCase()
);
hasRequiredRole = roles.includes(roleType);
}
return [hasRequiredRole];
};
ÉCHANTILLON DE JETON JWT DÉCODÉ
{
"authorization": {
"roles": [
"admin",
"operator"
]
},
"exp": 1591733170,
"user_id": 1,
"orig_iat": 1591646770,
"email": "hemanthvrm@stackoverflow",
"username": "hemanthvrm"
}
0 votes
Le mieux est de le faire sur componetWillMount si vous n'utilisez pas le rendu côté serveur.
0 votes
@mfahadi, merci pour votre contribution. Je n'utilise pas encore SSR, mais si je veux l'utiliser à l'avenir, dois-je le garder dans le rendu ? De plus, si l'utilisateur est redirigé dans
componentWillMount
Pourront-ils jamais voir le résultat rendu, même une fraction de seconde ?0 votes
Je suis vraiment désolé de dire ça
componentWillMount()
n'est pas appelé sur SSR, il estcomponentDidMount()
qui n'est pas appelé. commecomponentWillMount()
est appelé avantrender()
L'utilisateur ne verra donc pas de nouveau composant. C'est donc le meilleur endroit pour vérifier.1 votes
Vous pourriez simplement utiliser le
<Redirect to="/auth">
à partir de la documentation au lieu d'appeler l'action de répartition0 votes
Par curiosité, est-ce que quelqu'un a trouvé une façon propre de faire le inverser de ce que l'OP demande ? c'est-à-dire comment déclarer une route comme
/login
c'est-à-dire seulement accessible si l'utilisateur n'est PAS connecté/authentifié ?