(Menggunakan Redux untuk manajemen negara)
Jika pengguna mencoba mengakses url apa pun, pertama-tama saya akan memeriksa apakah token akses tersedia, jika tidak dialihkan ke halaman login, Setelah pengguna masuk menggunakan halaman login, kami menyimpannya di penyimpanan lokal dan juga di status redux kami. (penyimpanan lokal atau cookie..kami merahasiakan topik ini dari konteksnya untuk saat ini).
karena status redux sebagai diperbarui dan privateroutes akan dirender. sekarang kami memiliki token akses sehingga kami akan mengarahkan ke halaman beranda.
Simpan juga data payload otorisasi yang didekode dalam status redux dan teruskan ke konteks reaksi. (Kami tidak harus menggunakan konteks tetapi untuk mengakses otorisasi di salah satu komponen turunan bersarang kami, ini memudahkan akses dari konteks alih-alih menghubungkan setiap komponen turunan ke redux) ..
Semua rute yang tidak memerlukan peran khusus dapat diakses langsung setelah login .. Jika membutuhkan peran seperti admin (kami membuat rute yang dilindungi yang memeriksa apakah dia memiliki peran yang diinginkan jika tidak dialihkan ke komponen yang tidak sah)
Demikian pula di salah satu komponen Anda jika Anda harus menonaktifkan tombol atau sesuatu berdasarkan peran.
sederhana yang dapat Anda lakukan dengan cara ini
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>
Jadi bagaimana jika pengguna mencoba memasukkan token dummy di penyimpanan lokal. Karena kami memiliki token akses, kami akan mengarahkan ke komponen rumah. Komponen rumah saya akan membuat panggilan istirahat untuk mengambil data, karena token jwt adalah dummy, panggilan istirahat akan mengembalikan pengguna yang tidak sah. Jadi saya memanggil logout (yang akan menghapus penyimpanan lokal dan mengarahkan ke halaman login lagi). Jika halaman beranda memiliki data statis dan tidak melakukan panggilan api apa pun (maka Anda harus memiliki panggilan api verifikasi-token di backend sehingga Anda dapat memeriksa apakah token itu NYATA sebelum memuat halaman beranda)
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];
};
CONTOH JWT TOKEN DEKODASI
{
"authorization": {
"roles": [
"admin",
"operator"
]
},
"exp": 1591733170,
"user_id": 1,
"orig_iat": 1591646770,
"email": "hemanthvrm@stackoverflow",
"username": "hemanthvrm"
}