(Utilizzo di Redux per la gestione dello stato)
Se l'utente tenta di accedere a qualsiasi URL, per prima cosa controllerò se il token di accesso è disponibile, se non reindirizzerò alla pagina di accesso. Una volta che l'utente accede utilizzando la pagina di accesso, lo memorizziamo in localstorage e nel nostro stato di redux. (localstorage o cookies .. per ora teniamo questo argomento fuori contesto).
dal momento che lo stato di redux come aggiornato e privateroutes verranno riesaminati. ora abbiamo il token di accesso, quindi reindirizzeremo alla home page.
Memorizza anche i dati del payload dell'autorizzazione decodificata nello stato redux e passali al contesto di reazione. (Non dobbiamo usare il contesto ma per accedere all'autorizzazione in nessuno dei nostri componenti figlio nidificati rende facile l'accesso dal contesto invece di collegare ogni singolo componente figlio a redux) ..
È possibile accedere a tutte le rotte che non necessitano di ruoli speciali direttamente dopo il login .. Se ha bisogno di un ruolo come admin (abbiamo creato una rotta protetta che controlla se aveva il ruolo desiderato se non reindirizza a componenti non autorizzati)
allo stesso modo in qualsiasi componente se devi disabilitare il pulsante o qualcosa in base al ruolo.
semplicemente puoi farlo in questo modo
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>
Che cosa succede se l'utente tenta di inserire un token fittizio in localstorage. Poiché abbiamo il token di accesso, reindirizzeremo al componente home. Il mio componente home effettuerà una chiamata rest per acquisire i dati, poiché il token jwt era fittizio, la chiamata rest restituirà un utente non autorizzato. Quindi chiamo logout (che cancellerà localstorage e reindirizzerà nuovamente alla pagina di accesso). Se la home page ha dati statici e non effettua alcuna chiamata API (allora dovresti avere una chiamata API per la verifica del token nel backend in modo da poter controllare se il token è REALE prima di caricare la home page)
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];
};
CAMPIONE DI GETTONI JWT DECODIFICATO
{
"authorization": {
"roles": [
"admin",
"operator"
]
},
"exp": 1591733170,
"user_id": 1,
"orig_iat": 1591646770,
"email": "hemanthvrm@stackoverflow",
"username": "hemanthvrm"
}