How to handle Authentication with react-router?

后端 未结 2 1798
野的像风
野的像风 2020-12-06 15:44

Trying to make certain routes require Authentication.

I have this:

class App extends Component {
  render() {
    const menuClass = `${this.props.c         


        
2条回答
  •  自闭症患者
    2020-12-06 16:21

    A simple solution would be to make a HOC (High Order Component) that wraps all protected routes.

    Depending upon how nested your app is, you may want to utilize local state or redux state.

    Working example: https://codesandbox.io/s/5m2690nn6n (this uses local state)

    routes/index.js

    import React from "react";
    import { BrowserRouter, Switch, Route } from "react-router-dom";
    import Home from "../components/Home";
    import Players from "../components/Players";
    import Schedule from "../components/Schedule";
    import RequireAuth from "../components/RequireAuth";
    
    export default () => (
      
        
          
            
            
            
          
        
      
    );
    

    components/RequireAuth.js

    import React, { Component, Fragment } from "react";
    import { withRouter } from "react-router-dom";
    import Login from "./Login";
    import Header from "./Header";
    
    class RequireAuth extends Component {
      state = { isAuthenticated: false };
    
      componentDidMount = () => {
        if (!this.state.isAuthenticated) {
          this.props.history.push("/");
        }
      };
    
      componentDidUpdate = (prevProps, prevState) => {
        if (
          this.props.location.pathname !== prevProps.location.pathname &&
          !this.state.isAuthenticated
        ) {
          this.props.history.push("/");
        }
      };
    
      isAuthed = () => this.setState({ isAuthenticated: true });
    
      unAuth = () => this.setState({ isAuthenticated: false });
    
      render = () =>
        !this.state.isAuthenticated ? (
          
        ) : (
          
            
    {this.props.children} ); } export default withRouter(RequireAuth);

    Or, instead of wrapping routes, you can create a protected component that houses protected routes.

    Working example: https://codesandbox.io/s/yqo75n896x (uses redux instead of local state).

    routes/index.js

    import React from "react";
    import { BrowserRouter, Route, Switch } from "react-router-dom";
    import { createStore } from "redux";
    import { Provider } from "react-redux";
    import Home from "../components/Home";
    import Header from "../containers/Header";
    import Info from "../components/Info";
    import Sponsors from "../components/Sponsors";
    import Signin from "../containers/Signin";
    import RequireAuth from "../containers/RequireAuth";
    import rootReducer from "../reducers";
    
    const store = createStore(rootReducer);
    
    export default () => (
      
        
          
    );

    containers/RequireAuth.js

    import React from "react";
    import { Route, Redirect } from "react-router-dom";
    import { connect } from "react-redux";
    import ShowPlayerRoster from "../components/ShowPlayerRoster";
    import ShowPlayerStats from "../components/ShowPlayerStats";
    import Schedule from "../components/Schedule";
    
    const RequireAuth = ({ match: { path }, isAuthenticated }) =>
      !isAuthenticated ? (
        
      ) : (
        
    ); export default connect(state => ({ isAuthenticated: state.auth.isAuthenticated }))(RequireAuth);

    You can even get more modular by creating a wrapper function. You would be able to pick and choose any route by simply wrapping over the component. I don't have a codebox example, but it would be similar to this setup.

    For example:

提交回复
热议问题