(Używanie Redux do zarządzania stanem)
Jeśli użytkownik spróbuje uzyskać dostęp do dowolnego adresu URL, najpierw sprawdzę, czy token dostępu jest dostępny, jeśli nie przekieruje do strony logowania. Gdy użytkownik zaloguje się za pomocą strony logowania, przechowujemy go w magazynie lokalnym, a także w naszym stanie redux. (Localstorage lub cookies… na razie trzymamy ten temat poza kontekstem).
ponieważ stan Redux jako zaktualizowany, a prywatne trasy zostaną ponownie wyrenderowane. teraz mamy token dostępu, więc przekierujemy na stronę główną.
Przechowuj również zdekodowane dane ładunku autoryzacji w stanie redux i przekaż je do kontekstu reakcji. (Nie musimy używać kontekstu, ale aby uzyskać dostęp do autoryzacji w dowolnym z naszych zagnieżdżonych komponentów podrzędnych, ułatwia to dostęp z kontekstu zamiast łączenia każdego komponentu podrzędnego z reduxem).
Wszystkie trasy, które nie wymagają specjalnych ról, można uzyskać bezpośrednio po zalogowaniu .. Jeśli potrzebna jest rola, np. Admin (stworzyliśmy chronioną trasę, która sprawdza, czy miał pożądaną rolę, jeśli nie przekierowuje do nieautoryzowanego komponentu)
podobnie w każdym komponencie, jeśli musisz wyłączyć przycisk lub coś w oparciu o rolę.
po prostu możesz to zrobić w ten sposób
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>
A co, jeśli użytkownik spróbuje wstawić fikcyjny token w localstorage. Ponieważ mamy token dostępu, przekierujemy do komponentu domowego. Mój komponent domowy wykona wywołanie rest w celu pobrania danych, ponieważ token jwt był fikcyjny, wywołanie rest zwróci nieautoryzowanego użytkownika. Więc wywołuję wylogowanie (co wyczyści localstorage i ponownie przekieruje do strony logowania). Jeśli strona główna ma dane statyczne i nie wykonuje żadnych wywołań API (wtedy powinieneś mieć wywołanie api token-weryfikacja w zapleczu, abyś mógł sprawdzić, czy token jest PRAWDZIWY przed załadowaniem strony głównej)
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];
};
ODKODOWANA PRÓBKA TOKENU JWT
{
"authorization": {
"roles": [
"admin",
"operator"
]
},
"exp": 1591733170,
"user_id": 1,
"orig_iat": 1591646770,
"email": "hemanthvrm@stackoverflow",
"username": "hemanthvrm"
}