(Sử dụng Redux để quản lý nhà nước)
Nếu người dùng cố gắng truy cập bất kỳ url nào, trước tiên tôi sẽ kiểm tra xem mã thông báo truy cập có sẵn không, nếu không chuyển hướng đến trang đăng nhập, Khi người dùng đăng nhập bằng trang đăng nhập, chúng tôi sẽ lưu trữ trong trạng thái lưu trữ cục bộ cũng như trong trạng thái redux của chúng tôi. (lưu trữ cục bộ hoặc cookie..chúng tôi giữ chủ đề này ra khỏi bối cảnh bây giờ).
kể từ khi trạng thái redux như được cập nhật và quyền riêng tư sẽ được đăng ký lại. bây giờ chúng tôi có mã thông báo truy cập vì vậy chúng tôi sẽ chuyển hướng đến trang chủ.
Lưu trữ dữ liệu tải trọng ủy quyền được giải mã cũng ở trạng thái redux và chuyển nó để phản ứng bối cảnh. (Chúng tôi không phải sử dụng ngữ cảnh nhưng để truy cập ủy quyền trong bất kỳ thành phần con lồng nhau nào của chúng tôi, điều đó giúp dễ dàng truy cập từ ngữ cảnh thay vì kết nối từng thành phần con với redux) ..
Tất cả các tuyến không cần vai trò đặc biệt đều có thể được truy cập trực tiếp sau khi đăng nhập .. Nếu cần vai trò như quản trị viên (chúng tôi đã thực hiện tuyến được bảo vệ để kiểm tra xem anh ta có vai trò mong muốn hay không nếu không chuyển hướng đến thành phần trái phép)
tương tự trong bất kỳ thành phần nào của bạn nếu bạn phải tắt nút hoặc một cái gì đó dựa trên vai trò.
đơn giản là bạn có thể làm theo cách này
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>
Vậy điều gì sẽ xảy ra nếu người dùng cố gắng chèn mã thông báo giả trong localst Storage. Khi chúng tôi có mã thông báo truy cập, chúng tôi sẽ chuyển hướng đến thành phần nhà. Thành phần nhà của tôi sẽ thực hiện cuộc gọi nghỉ ngơi để lấy dữ liệu, vì mã thông báo jwt là giả, cuộc gọi còn lại sẽ trả lại người dùng trái phép. Vì vậy, tôi thực hiện đăng xuất cuộc gọi (sẽ xóa cục bộ và chuyển hướng đến trang đăng nhập một lần nữa). Nếu trang chủ có dữ liệu tĩnh và không thực hiện bất kỳ cuộc gọi api nào (thì bạn nên có cuộc gọi api xác minh mã thông báo trong phần phụ trợ để bạn có thể kiểm tra xem mã thông báo có THỰC SỰ trước khi tải trang chủ không)
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')
);
Lịch sử.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];
};
MẪU JWT TOKEN
{
"authorization": {
"roles": [
"admin",
"operator"
]
},
"exp": 1591733170,
"user_id": 1,
"orig_iat": 1591646770,
"email": "hemanthvrm@stackoverflow",
"username": "hemanthvrm"
}