Wie implementiere ich authentifizierte Routen in React Router 4?

121

Ich habe versucht, authentifizierte Routen zu implementieren, aber festgestellt, dass React Router 4 dies jetzt verhindert:

<Route exact path="/" component={Index} />
<Route path="/auth" component={UnauthenticatedWrapper}>
    <Route path="/auth/login" component={LoginBotBot} />
</Route>
<Route path="/domains" component={AuthenticatedWrapper}>
    <Route exact path="/domains" component={DomainsIndex} />
</Route>

Der Fehler ist:

Warnung: Sie sollten nicht <Route component>und <Route children>auf derselben Route verwenden. <Route children>wird ignoriert

Was ist in diesem Fall der richtige Weg, um dies umzusetzen?

Es erscheint in react-router(v4) Dokumenten, es schlägt so etwas vor

<Router>
    <div>
    <AuthButton/>
    <ul>
        <li><Link to="/public">Public Page</Link></li>
        <li><Link to="/protected">Protected Page</Link></li>
    </ul>
    <Route path="/public" component={Public}/>
    <Route path="/login" component={Login}/>
    <PrivateRoute path="/protected" component={Protected}/>
    </div>
</Router>

Aber ist es möglich, dies zu erreichen, während mehrere Routen zusammengefasst werden?


AKTUALISIEREN

Ok, nach einigen Recherchen habe ich mir Folgendes ausgedacht:

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

export default class AuthenticatedRoute extends React.Component {
  render() {
    if (!this.props.isLoggedIn) {
      this.props.redirectToLogin()
      return null
    }
    return <Route {...this.props} />
  }
}

AuthenticatedRoute.propTypes = {
  isLoggedIn: PropTypes.bool.isRequired,
  component: PropTypes.element,
  redirectToLogin: PropTypes.func.isRequired
}

Ist es richtig, eine Aktion auszulösen, render()fühlt es sich falsch an. Es scheint nicht wirklich richtig mit componentDidMountoder einem anderen Haken?

Jiew Meng
quelle
Am besten mit componentWillMount, wenn kein serverseitiges Rendering verwendet wird.
Mfahadi
@mfahadi, danke für die Eingabe. Ich verwende SSR noch nicht, aber wenn ich es in Zukunft verwenden möchte, behalte ich es beim Rendern? Auch wenn der Benutzer umgeleitet componentWillMountwird, kann er die gerenderte Ausgabe auch nur für den Bruchteil einer Sekunde sehen?
Jiew Meng
Es tut mir wirklich leid zu sagen, dass componentWillMount()SSR nicht aufgerufen wird, sondern componentDidMount()nicht. Wie componentWillMount()zuvor genannt render(), sieht der Benutzer nichts von einer neuen Komponente. Es ist also der beste Ort, um nachzusehen.
Mfahadi
1
Sie können einfach die <Redirect to="/auth"> aus den Dokumenten verwenden, anstatt die Versandaktion
aufzurufen

Antworten:

238

Sie werden die RedirectKomponente verwenden wollen. Es gibt verschiedene Ansätze für dieses Problem. Hier ist eine, die mir gefällt: Ich habe eine PrivateRoute-Komponente, die eine authedRequisite aufnimmt und dann basierend auf diesen Requisiten rendert.

function PrivateRoute ({component: Component, authed, ...rest}) {
  return (
    <Route
      {...rest}
      render={(props) => authed === true
        ? <Component {...props} />
        : <Redirect to={{pathname: '/login', state: {from: props.location}}} />}
    />
  )
}

Jetzt kann dein Routes so aussehen

<Route path='/' exact component={Home} />
<Route path='/login' component={Login} />
<Route path='/register' component={Register} />
<PrivateRoute authed={this.state.authed} path='/dashboard' component={Dashboard} />

Wenn Sie immer noch verwirrt sind, habe ich diesen Beitrag geschrieben, der möglicherweise hilft - Geschützte Routen und Authentifizierung mit React Router v4

Tyler McGinnis
quelle
2
Oh, das ist ähnlich wie meine Lösung, aber es verwendet <Redirect />. Das Problem ist, <Redirect />scheint in meinem Fall nicht mit Redux zu funktionieren? Ich muss eine Aktion
auslösen
3
Ich weiß nicht warum, aber das Hinzufügen state: {from: props.location}}}verursachte a maximum call stack exceeded. Ich musste es entfernen. Können Sie erklären, warum diese Option bei Tyler McGinnis nützlich ist?
Martpie
@ KeitIG ​​Das ist seltsam. Es ist nützlich, weil es Ihnen sagt, woher Sie kamen. Ein Beispiel wäre, wenn Sie möchten, dass sich der Benutzer authentifiziert. Sobald er sich authentifiziert hat, kehren Sie zu der Seite zurück, auf die er zugreifen wollte, bevor Sie ihn umleiten.
Tyler McGinnis
6
@faraz Dies erklärt die ({component: Component, ...rest})Syntax. Ich hatte die gleiche Frage lol! stackoverflow.com/a/43484565/6502003
protoEvangelion
2
@ TylerMcGinnis Was ist, wenn wir die Renderfunktion zum Übergeben von Requisiten an die Komponente verwenden müssen?
C Bauer
16

Tnx Tyler McGinnis für die Lösung. Ich mache meine Idee von Tyler McGinnis Idee.

const DecisionRoute = ({ trueComponent, falseComponent, decisionFunc, ...rest }) => {
  return (
    <Route
      {...rest}

      render={
        decisionFunc()
          ? trueComponent
          : falseComponent
      }
    />
  )
}

Sie können das so implementieren

<DecisionRoute path="/signin" exact={true}
            trueComponent={redirectStart}
            falseComponent={SignInPage}
            decisionFunc={isAuth}
          />

DecisionFunc ist nur eine Funktion, die true oder false zurückgibt

const redirectStart = props => <Redirect to="/orders" />
MrDuDuDu
quelle
8

(Verwenden von Redux für die Statusverwaltung)

Wenn der Benutzer versucht, auf eine URL zuzugreifen, werde ich zuerst prüfen, ob ein Zugriffstoken verfügbar ist. Wenn nicht, wird er zur Anmeldeseite umgeleitet. Sobald sich der Benutzer über die Anmeldeseite anmeldet, speichern wir diese sowohl in localstorage als auch in unserem Redux-Status. (localstorage oder Cookies. Wir halten dieses Thema vorerst aus dem Kontext).
da Redux-Status als aktualisiert und Privaterouten neu gerendert werden. Jetzt haben wir Zugriffstoken, sodass wir zur Startseite weiterleiten können.

Speichern Sie die dekodierten Berechtigungsnutzdaten auch im Redux-Status und übergeben Sie sie an den Reaktionskontext. (Wir müssen keinen Kontext verwenden, aber um auf die Autorisierung in einer unserer verschachtelten untergeordneten Komponenten zuzugreifen, ist der Zugriff über den Kontext einfach, anstatt jede untergeordnete Komponente mit Redux zu verbinden.)

Auf alle Routen, die keine speziellen Rollen benötigen, kann direkt nach der Anmeldung zugegriffen werden. Wenn eine Rolle wie admin benötigt wird (wir haben eine geschützte Route erstellt, die prüft, ob er die gewünschte Rolle hatte, wenn er nicht zu einer nicht autorisierten Komponente umleitet).

Ähnliches gilt für jede Ihrer Komponenten, wenn Sie die Schaltfläche oder etwas basierend auf der Rolle deaktivieren müssen.

einfach können Sie auf diese Weise tun

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>

Was ist, wenn der Benutzer versucht, ein Dummy-Token in localstorage einzufügen? Da wir über ein Zugriffstoken verfügen, werden wir zur Home-Komponente umleiten. Meine Home-Komponente führt einen Restaufruf durch, um Daten abzurufen. Da das JWT-Token ein Dummy war, gibt der Restaufruf einen nicht autorisierten Benutzer zurück. Also rufe ich die Abmeldung auf (wodurch localstorage gelöscht und erneut zur Anmeldeseite umgeleitet wird). Wenn die Homepage statische Daten enthält und keine API-Aufrufe tätigt (dann sollten Sie im Backend einen API-Aufruf zur Token-Überprüfung haben, damit Sie überprüfen können, ob das Token REAL ist, bevor Sie die Homepage laden).

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];
};

DEKODIERTE JWT-TOKEN-PROBE

{
  "authorization": {
    "roles": [
      "admin",
      "operator"
    ]
  },
  "exp": 1591733170,
  "user_id": 1,
  "orig_iat": 1591646770,
  "email": "hemanthvrm@stackoverflow",
  "username": "hemanthvrm"
}
Hemanthvrm
quelle
Und wie gehen Sie mit dem direkten Zugriff auf um Signin? Wenn ein Benutzer weiß, dass er nicht angemeldet ist, sollte er die Möglichkeit haben, direkt auf die Anmeldung zuzugreifen, oder?
Carkod
@carkod ... Wenn er versucht, auf eine Route zuzugreifen, wird er standardmäßig zur Anmeldeseite weitergeleitet ... (da er
kein
@carkod .. Sobald der Benutzer auf Abmelden geklickt hat oder mein JWT-Aktualisierungstoken abläuft, rufe ich die Abmeldefunktion auf, bei der ich das lokale Speicher- und Aktualisierungsfenster lösche. Daher hat localstorage kein Token. Es wird automatisch zur Anmeldeseite umgeleitet
Hemanthvrm
Ich habe eine bessere Version davon für diejenigen, die Redux verwenden. Ich werde meine Antwort in ein paar Tagen aktualisieren. Danke -
Hemanthvrm
3

Installieren Sie React-Router-Dom

Erstellen Sie dann zwei Komponenten, eine für gültige Benutzer und eine für ungültige Benutzer.

Versuchen Sie dies auf app.js.

import React from 'react';

import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect
} from 'react-router-dom';

import ValidUser from "./pages/validUser/validUser";
import InValidUser from "./pages/invalidUser/invalidUser";
const loggedin = false;

class App extends React.Component {
 render() {
    return ( 
      <Router>
      <div>
        <Route exact path="/" render={() =>(
          loggedin ? ( <Route  component={ValidUser} />)
          : (<Route component={InValidUser} />)
        )} />

        </div>
      </Router>
    )
  }
}
export default App;
Jose G Varanam
quelle
4
Pro Route? Dies wird nicht skaliert.
Jim G.
3

Basierend auf der Antwort von @Tyler McGinnis . Ich habe einen anderen Ansatz mit ES6-Syntax und verschachtelten Routen mit umschlossenen Komponenten gewählt:

import React, { cloneElement, Children } from 'react'
import { Route, Redirect } from 'react-router-dom'

const PrivateRoute = ({ children, authed, ...rest }) =>
  <Route
    {...rest}
    render={(props) => authed ?
      <div>
        {Children.map(children, child => cloneElement(child, { ...child.props }))}
      </div>
      :
      <Redirect to={{ pathname: '/', state: { from: props.location } }} />}
  />

export default PrivateRoute

Und damit:

<BrowserRouter>
  <div>
    <PrivateRoute path='/home' authed={auth}>
      <Navigation>
        <Route component={Home} path="/home" />
      </Navigation>
    </PrivateRoute>

    <Route exact path='/' component={PublicHomePage} />
  </div>
</BrowserRouter>
Felipe Augusto
quelle
2

Ich weiß, dass es eine Weile her ist, aber ich habe an einem npm-Paket gearbeitet für private und öffentliche Strecken gearbeitet.

So erstellen Sie eine private Route:

<PrivateRoute exact path="/private" authed={true} redirectTo="/login" component={Title} text="This is a private route"/>

Sie können auch öffentliche Routen erstellen, auf die nur nicht autorisierte Benutzer zugreifen können

<PublicRoute exact path="/public" authed={false} redirectTo="/admin" component={Title} text="This route is for unauthed users"/>

Ich hoffe, es hilft!

Gonzalo Cañada
quelle
Können Sie bitte weitere Beispiele einschließlich aller Importe und Wraps, z. B. in 2 öffentlichen Routen, 2 privaten Routen und 2 PropsRoute, in der Haupt-App.js angeben? Vielen Dank
MH
2

Ich implementierte mit-

<Route path='/dashboard' render={() => (
    this.state.user.isLoggedIn ? 
    (<Dashboard authenticate={this.authenticate} user={this.state.user} />) : 
    (<Redirect to="/login" />)
)} />

Authentifizierungs-Requisiten werden an Komponenten übergeben, z. B. die Anmeldung, mit der der Benutzerstatus geändert werden kann. Komplette AppRoutes-

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

import Home from '../pages/home';
import Login from '../pages/login';
import Signup from '../pages/signup';
import Dashboard from '../pages/dashboard';

import { config } from '../utils/Config';

export default class AppRoutes extends React.Component {

    constructor(props) {
        super(props);

        // initially assuming that user is logged out
        let user = {
            isLoggedIn: false
        }

        // if user is logged in, his details can be found from local storage
        try {
            let userJsonString = localStorage.getItem(config.localStorageKey);
            if (userJsonString) {
                user = JSON.parse(userJsonString);
            }
        } catch (exception) {
        }

        // updating the state
        this.state = {
            user: user
        };

        this.authenticate = this.authenticate.bind(this);
    }

    // this function is called on login/logout
    authenticate(user) {
        this.setState({
            user: user
        });

        // updating user's details
        localStorage.setItem(config.localStorageKey, JSON.stringify(user));
    }

    render() {
        return (
            <Switch>
                <Route exact path='/' component={Home} />
                <Route exact path='/login' render={() => <Login authenticate={this.authenticate} />} />
                <Route exact path='/signup' render={() => <Signup authenticate={this.authenticate} />} />
                <Route path='/dashboard' render={() => (
                    this.state.user.isLoggedIn ? 
                            (<Dashboard authenticate={this.authenticate} user={this.state.user} />) : 
                            (<Redirect to="/login" />)
                )} />
            </Switch>
        );
    }
} 

Überprüfen Sie das vollständige Projekt hier: https://github.com/varunon9/hello-react

Varun Kumar
quelle
1

Es scheint, dass Sie zögern, Ihre eigene Komponente zu erstellen und dann in der Rendermethode zu versenden? Nun, Sie können beides vermeiden, indem Sie nur die renderMethode der <Route>Komponente verwenden. Sie müssen keine <AuthenticatedRoute>Komponente erstellen, es sei denn, Sie möchten dies wirklich. Es kann so einfach wie unten sein. Beachten Sie den {...routeProps}Spread, um sicherzustellen, dass Sie die Eigenschaften der <Route>Komponente weiterhin an die untergeordnete Komponente senden ( <MyComponent>in diesem Fall).

<Route path='/someprivatepath' render={routeProps => {

   if (!this.props.isLoggedIn) {
      this.props.redirectToLogin()
      return null
    }
    return <MyComponent {...routeProps} anotherProp={somevalue} />

} />

Siehe die Informationen finden Renderdokumentation zu React Router V4

Wenn Sie eine dedizierte Komponente erstellen wollten, scheinen Sie auf dem richtigen Weg zu sein. Da es sich bei React Router V4 um ein rein deklaratives Routing handelt (wie in der Beschreibung angegeben), werden Sie Ihren Redirect-Code wahrscheinlich nicht außerhalb des normalen Komponentenlebenszyklus platzieren. Wenn Sie sich den Code für React Router selbst ansehen , führen sie die Umleitung entweder in componentWillMountoder componentDidMountabhängig davon durch, ob es sich um serverseitiges Rendering handelt oder nicht. Hier ist der folgende Code, der ziemlich einfach ist und Ihnen helfen kann, sich wohler zu fühlen, wo Sie Ihre Umleitungslogik platzieren sollen.

import React, { PropTypes } from 'react'

/**
 * The public API for updating the location programatically
 * with a component.
 */
class Redirect extends React.Component {
  static propTypes = {
    push: PropTypes.bool,
    from: PropTypes.string,
    to: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.object
    ])
  }

  static defaultProps = {
    push: false
  }

  static contextTypes = {
    router: PropTypes.shape({
      history: PropTypes.shape({
        push: PropTypes.func.isRequired,
        replace: PropTypes.func.isRequired
      }).isRequired,
      staticContext: PropTypes.object
    }).isRequired
  }

  isStatic() {
    return this.context.router && this.context.router.staticContext
  }

  componentWillMount() {
    if (this.isStatic())
      this.perform()
  }

  componentDidMount() {
    if (!this.isStatic())
      this.perform()
  }

  perform() {
    const { history } = this.context.router
    const { push, to } = this.props

    if (push) {
      history.push(to)
    } else {
      history.replace(to)
    }
  }

  render() {
    return null
  }
}

export default Redirect
Todd Chaffee
quelle
1

Meine vorherige Antwort ist nicht skalierbar. Folgendes halte ich für einen guten Ansatz:

Ihre Routen-

<Switch>
  <Route
    exact path="/"
    component={matchStateToProps(InitialAppState, {
      routeOpen: true // no auth is needed to access this route
    })} />
  <Route
    exact path="/profile"
    component={matchStateToProps(Profile, {
      routeOpen: false // can set it false or just omit this key
    })} />
  <Route
    exact path="/login"
    component={matchStateToProps(Login, {
      routeOpen: true
    })} />
  <Route
    exact path="/forgot-password"
    component={matchStateToProps(ForgotPassword, {
      routeOpen: true
    })} />
  <Route
    exact path="/dashboard"
    component={matchStateToProps(DashBoard)} />
</Switch>

Die Idee ist, einen Wrapper in componentRequisiten zu verwenden, der die Originalkomponente zurückgibt, wenn keine Authentifizierung erforderlich ist oder bereits authentifiziert wurde. Andernfalls wird die Standardkomponente zurückgegeben, z. B. Login.

const matchStateToProps = function(Component, defaultProps) {
  return (props) => {
    let authRequired = true;

    if (defaultProps && defaultProps.routeOpen) {
      authRequired = false;
    }

    if (authRequired) {
      // check if loginState key exists in localStorage (Your auth logic goes here)
      if (window.localStorage.getItem(STORAGE_KEYS.LOGIN_STATE)) {
        return <Component { ...defaultProps } />; // authenticated, good to go
      } else {
        return <InitialAppState { ...defaultProps } />; // not authenticated
      }
    }
    return <Component { ...defaultProps } />; // no auth is required
  };
};
Varun Kumar
quelle
Wenn keine Authentifizierung erforderlich ist, übergeben Sie die Komponente nicht an die Funktion matchStateToProps. Damit entfällt die Notwendigkeit des RouteOpen-Flags
Dheeraj,
1

Hier ist die einfache, saubere, geschützte Route

const ProtectedRoute 
  = ({ isAllowed, ...props }) => 
     isAllowed 
     ? <Route {...props}/> 
     : <Redirect to="/authentificate"/>;
const _App = ({ lastTab, isTokenVerified })=> 
    <Switch>
      <Route exact path="/authentificate" component={Login}/>
      <ProtectedRoute 
         isAllowed={isTokenVerified} 
         exact 
         path="/secrets" 
         component={Secrets}/>
      <ProtectedRoute 
         isAllowed={isTokenVerified} 
         exact 
         path="/polices" 
         component={Polices}/>
      <ProtectedRoute 
         isAllowed={isTokenVerified} 
         exact 
         path="/grants" component={Grants}/>
      <Redirect from="/" to={lastTab}/>
    </Switch>

isTokenVerified ist ein Methodenaufruf zum Überprüfen des Autorisierungstokens, der im Grunde genommen boolesch zurückgibt.

Anupam Maurya
quelle
Dies ist die einzige Lösung, die ich hier gefunden habe, um zu funktionieren, wenn Sie eine Komponente oder untergeordnete Elemente an die Route übergeben.
Shawn
Hinweis: Ich habe gerade mein isTokenVerified () in meiner ProtectedRoute-Funktion aufgerufen und musste die isAllowed-Requisite nicht auf allen Routen übergeben.
Shawn
1

Hier ist, wie ich es mit React und Typescript gelöst habe. Ich hoffe es hilft !

import * as React from 'react';
import { Route, RouteComponentProps, RouteProps, Redirect } from 'react-router';

const PrivateRoute: React.SFC<RouteProps> = ({ component: Component, ...rest }) => {
    if (!Component) {
      return null;
    }
    const isLoggedIn = true; // Add your provider here
    return (
      <Route
        {...rest}
            render={(props: RouteComponentProps<{}>) => isLoggedIn ? (<Component {...props} />) : (<Redirect to={{ pathname: '/', state: { from: props.location } }} />)}
      />
    );
  };

export default PrivateRoute;








<PrivateRoute component={SignIn} path="/signin" />

Max_Thom
quelle
0
const Root = ({ session }) => {
  const isLoggedIn = session && session.getCurrentUser
  return (
    <Router>
      {!isLoggedIn ? (
        <Switch>
          <Route path="/signin" component={<Signin />} />
          <Redirect to="/signin" />
        </Switch>
      ) : (
        <Switch>
          <Route path="/" exact component={Home} />
          <Route path="/about" component={About} />
          <Route path="/something-else" component={SomethingElse} />
          <Redirect to="/" />
        </Switch>
      )}
    </Router>
  )
}
Fremder
quelle
0

Ich suchte auch nach einer Antwort. Hier sind alle Antworten recht gut, aber keine gibt Antworten darauf, wie wir sie verwenden können, wenn der Benutzer die Anwendung nach dem Öffnen wieder startet. (Ich wollte sagen, Cookie zusammen zu verwenden).

Sie müssen nicht einmal eine andere privateRoute-Komponente erstellen. Unten ist mein Code

    import React, { Component }  from 'react';
    import { Route, Switch, BrowserRouter, Redirect } from 'react-router-dom';
    import { Provider } from 'react-redux';
    import store from './stores';
    import requireAuth from './components/authentication/authComponent'
    import SearchComponent from './components/search/searchComponent'
    import LoginComponent from './components/login/loginComponent'
    import ExampleContainer from './containers/ExampleContainer'
    class App extends Component {
    state = {
     auth: true
    }


   componentDidMount() {
     if ( ! Cookies.get('auth')) {
       this.setState({auth:false });
     }
    }
    render() {
     return (
      <Provider store={store}>
       <BrowserRouter>
        <Switch>
         <Route exact path="/searchComponent" component={requireAuth(SearchComponent)} />
         <Route exact path="/login" component={LoginComponent} />
         <Route exact path="/" component={requireAuth(ExampleContainer)} />
         {!this.state.auth &&  <Redirect push to="/login"/> }
        </Switch>
       </BrowserRouter>
      </Provider>);
      }
     }
    }
    export default App;

Und hier ist authComponent

import React  from 'react';
import { withRouter } from 'react-router';
import * as Cookie from "js-cookie";
export default function requireAuth(Component) {
class AuthenticatedComponent extends React.Component {
 constructor(props) {
  super(props);
  this.state = {
   auth: Cookie.get('auth')
  }
 }
 componentDidMount() {
  this.checkAuth();
 }
 checkAuth() {
  const location = this.props.location;
  const redirect = location.pathname + location.search;
  if ( ! Cookie.get('auth')) {
   this.props.history.push(`/login?redirect=${redirect}`);
  }
 }
render() {
  return Cookie.get('auth')
   ? <Component { ...this.props } />
   : null;
  }
 }
 return  withRouter(AuthenticatedComponent)
}

Unten habe ich einen Blog geschrieben, dort können Sie auch ausführlichere Erklärungen erhalten.

Erstellen Sie geschützte Routen in ReactJS

nirmal
quelle
0

Die Lösung, die letztendlich für meine Organisation am besten funktioniert hat, ist unten aufgeführt. Sie fügt lediglich eine Überprüfung des Renderns für die Sysadmin-Route hinzu und leitet den Benutzer zu einem anderen Hauptpfad der Anwendung weiter, wenn er nicht auf der Seite sein darf.

SysAdminRoute.tsx

import React from 'react';
import { Route, Redirect, RouteProps } from 'react-router-dom';
import AuthService from '../services/AuthService';
import { appSectionPageUrls } from './appSectionPageUrls';
interface IProps extends RouteProps {}
export const SysAdminRoute = (props: IProps) => {
    var authService = new AuthService();
    if (!authService.getIsSysAdmin()) { //example
        authService.logout();
        return (<Redirect to={{
            pathname: appSectionPageUrls.site //front-facing
        }} />);
    }
    return (<Route {...props} />);
}

Es gibt drei Hauptrouten für unsere Implementierung: die öffentlich zugängliche Site, den angemeldeten Client / die angemeldete App und die Sys-Admin-Tools unter / sysadmin. Sie werden basierend auf Ihrer 'Authentizität' umgeleitet und dies ist die Seite unter / sysadmin.

SysAdminNav.tsx

<Switch>
    <SysAdminRoute exact path={sysadminUrls.someSysAdminUrl} render={() => <SomeSysAdminUrl/> } />
    //etc
</Switch>
C Bauer
quelle