Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Snippet] - Authentication in React Router #92

Open
shanejix opened this issue Jan 19, 2022 · 0 comments
Open

[Snippet] - Authentication in React Router #92

shanejix opened this issue Jan 19, 2022 · 0 comments

Comments

@shanejix
Copy link
Owner

shanejix commented Jan 19, 2022

同步链接: https://www.shanejix.com/posts/[Snippet] - Authentication in React Router/

React Router V5

file tree

.
├── conponents
    └── Authentication.tsx
├── pages
    ├── Home.tsx
    ├── Login.tsx
    └── Management.tsx
├── routes
    ├── privateRoutes.tsx
    └── publicRoutes.tsx
├── App.tsx

App.tsx

import React, { useState } from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import publicRoutes from "./routes/publicRoutes";
import privateRoutes from "./routes/privateRoutes";
import Authentication from "./components/Authentication";

function App() {
  const [user, setUser] = useState({});

  const loginAsUser = () => {
    setUser({
      role: ["user"],
    });
  };

  return (
    <Router>
      <Switch>
        {publicRoutes.map(({ path, component: Component, ...route }) => (
          <Route
            key={path}
            path={path}
            render={(routeProps: any) => (
              <Component loginAsUser={loginAsUser} {...routeProps} />
            )}
            {...route}
          />
        ))}
        {privateRoutes.map((route) => (
          <Authentication key={route.path} {...route} user={user} />
        ))}
      </Switch>
    </Router>
  );
}

export default App;

publicRoutes.ts

import Login from "../pages/Login";
import Home from "../pages/Home";

const publicRoutes = [
  {
    path: "/login",
    component: Login,
    exact: true,
  },
  {
    path: "/",
    component: Home,
    exact: true,
  },
];

export default publicRoutes;

privateRoutes.ts

import Management from "../pages/Management";

const privateRoutes = [
  {
    path: "/management",
    component: Management,
    exact: true,
    role: "user",
    backUrl: "/login",
  },
];

export default privateRoutes;

Authentication.tsx

import React from "react";
import { Route, Redirect } from "react-router-dom";

function Authentication(props: any) {
  const {
    user: { role: userRole },
    role: routeRole,
    backUrl,
    ...otherProps
  } = props;

  // 如果用户有权限,就渲染对应的路由
  if (userRole && userRole.includes(routeRole)) {
    return <Route {...otherProps} />;
  } else {
    // 如果没有权限,返回配置的默认路由
    return <Redirect to={backUrl} />;
  }
}

export default Authentication;

注意:react-router-dom 所依赖的版本为 "^5.3.3",完整代码

React Router V6

file tree

├── conponents
    ├── AuthProvider.jsx
    ├── Navgation.jsx
    └── ProtectedRoute.tsx
├── hooks
    ├── useAuth.jsx
├── pages
    ├── Admin.jsx
    ├── Dashboard.jsx
    ├── Home.jsx
    └── NoMatch.jsx
├── stores
    ├── AuthContext.jsx
├── utils
    ├── fakeAuth.js
├── App.jsx
├── index.jsx
├── Router.jsx

App.jsx

import * as React from "react";
import AuthProvider from "./components/AuthProvider";
import Navigation from "./components/Navigation";
import Router from "./Router";

const App = () => {
  return (
    <AuthProvider>
      <h1>React Router V6</h1>
      <Navigation />
      <Router />
    </AuthProvider>
  );
};

export default App;

Router.jsx

import * as React from "react";
import { Routes, Route } from "react-router-dom";
import ProtectedRoute from "./components/ProtectedRoute";
import Home from "./pages/Home";
import Dashboard from "./pages/Dashboard";
import Admin from "./pages/Admin";
import NoMatch from "./pages/NoMatch";

const Router = () => {
  return (
    <Routes>
      <Route index element={<Home />} />
      <Route path="home" element={<Home />} />
      <Route
        path="dashboard"
        element={
          <ProtectedRoute>
            <Dashboard />
          </ProtectedRoute>
        }
      />
      <Route
        path="admin"
        element={
          <ProtectedRoute>
            <Admin />
          </ProtectedRoute>
        }
      />
      <Route path="*" element={<NoMatch />} />
    </Routes>
  );
};

export default Router;

AuthProvider.jsx

import * as React from "react";
import { useNavigate, useLocation } from "react-router-dom";
import AuthContext from "../stores/AuthContext";
import fakeAuth from "../utils/fakeAuth";

const AuthProvider = ({ children }) => {
  const navigate = useNavigate();
  const location = useLocation();

  const [token, setToken] = React.useState(null);

  const handleLogin = async () => {
    const token = await fakeAuth();

    setToken(token);

    const origin = location.state?.from?.pathname || "/dashboard";
    navigate(origin);
  };

  const handleLogout = () => {
    setToken(null);
  };

  const value = {
    token,
    onLogin: handleLogin,
    onLogout: handleLogout,
  };

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};

export default AuthProvider;

ProtectedRoute.jsx

import * as React from "react";
import { Navigate, useLocation } from "react-router-dom";
import useAuth from "../hooks/useAuth";

const ProtectedRoute = ({ children }) => {
  const { token } = useAuth();
  const location = useLocation();

  if (!token) {
    return <Navigate to="/home" replace state={{ from: location }} />;
  }

  return children;
};

export default ProtectedRoute;

注意:react-router-dom 所依赖的版本为 "^6.0.1",完整代码

作者:shanejix
出处:https://www.shanejix.com/posts/[Snippet] - Authentication in React Router/
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
声明:转载请注明出处!

@shanejix shanejix changed the title [Snippet] - react router authentication [Snippet] - React router authentication Jan 22, 2022
@shanejix shanejix changed the title [Snippet] - React router authentication [Snippet] - Authentication in React Router Feb 11, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant