(Usando Redux para la gestión del estado)
Si el usuario intenta acceder a cualquier URL, primero voy a verificar si el token de acceso está disponible, si no lo redirigir a la página de inicio de sesión, una vez que el usuario inicia sesión usando la página de inicio de sesión, lo almacenamos en el almacenamiento local así como en nuestro estado redux. (almacenamiento local o cookies ... mantenemos este tema fuera de contexto por ahora).
ya que el estado de redux como actualizado y las rutas privadas se volverán a generar. ahora tenemos token de acceso, así que lo redireccionaremos a la página de inicio.
Almacene los datos de carga útil de autorización decodificados también en estado redux y páselos al contexto de reacción. (No tenemos que usar el contexto, pero para acceder a la autorización en cualquiera de nuestros componentes secundarios anidados, es fácil acceder desde el contexto en lugar de conectar todos y cada uno de los componentes secundarios a redux).
Se puede acceder a todas las rutas que no necesitan roles especiales directamente después de iniciar sesión. Si necesita un rol como administrador (hicimos una ruta protegida que verifica si tenía el rol deseado o si no se redirige a un componente no autorizado)
de manera similar en cualquiera de sus componentes si tiene que deshabilitar el botón o algo basado en el rol.
simplemente puedes hacerlo de esta manera
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>
Entonces, ¿qué pasa si el usuario intenta insertar un token ficticio en localstorage? Como tenemos token de acceso, lo redireccionaremos al componente de inicio. Mi componente de inicio hará una llamada de descanso para obtener datos, ya que el token jwt era ficticio, la llamada de descanso devolverá al usuario no autorizado. Así que llamo al cierre de sesión (que borrará el almacenamiento local y redirigirá a la página de inicio de sesión nuevamente). Si la página de inicio tiene datos estáticos y no realiza ninguna llamada de API (entonces debe tener una llamada de API de verificación de token en el backend para que pueda verificar si el token es REAL antes de cargar la página de inicio)
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')
);
History.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];
};
MUESTRA DE TOKEN JWT DECODIFICADO
{
"authorization": {
"roles": [
"admin",
"operator"
]
},
"exp": 1591733170,
"user_id": 1,
"orig_iat": 1591646770,
"email": "hemanthvrm@stackoverflow",
"username": "hemanthvrm"
}