Bagaimana cara menerapkan rute yang diautentikasi di React Router 4?

122

Saya mencoba menerapkan rute yang diautentikasi tetapi menemukan bahwa React Router 4 sekarang mencegah ini berfungsi:

<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>

Kesalahannya adalah:

Peringatan: Anda tidak boleh menggunakan <Route component>dan <Route children>di rute yang sama; <Route children>akan diabaikan

Dalam hal ini, bagaimana cara yang benar untuk mengimplementasikannya?

Itu muncul di react-router(v4) dokumen, itu menyarankan sesuatu seperti

<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>

Tetapi apakah mungkin untuk mencapai ini sambil mengelompokkan sekelompok rute bersama?


MEMPERBARUI

Oke, setelah beberapa penelitian, saya menemukan ini:

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
}

Apakah benar mengirim tindakan di render()dalamnya terasa salah. Ini tidak benar-benar terlihat benar dengan componentDidMountatau beberapa kait lain juga?

Jiew Meng
sumber
paling baik dilakukan di komponetWillMount jika tidak menggunakan rendering sisi server.
mfahadi
@mfahadi terima kasih masukannya. Saya belum menggunakan SSR, tetapi jika saya ingin menggunakannya di masa mendatang, apakah saya menyimpannya dalam render? Juga jika pengguna dialihkan componentWillMount, apakah mereka akan pernah melihat keluaran yang diberikan bahkan untuk sepersekian detik?
Jiew Meng
Saya benar-benar minta maaf untuk mengatakan yang componentWillMount()tidak disebut di SSR, itu componentDidMount()yang tidak disebut. seperti componentWillMount()yang dipanggil sebelumnya render(), sehingga pengguna tidak akan melihat apa pun dari komponen baru. jadi ini adalah tempat terbaik untuk diperiksa.
mfahadi
1
Anda bisa menggunakan <Redirect to="/auth"> dari dokumen alih-alih memanggil tindakan pengiriman
Fuzail l'Corder

Jawaban:

239

Anda akan ingin menggunakan Redirectkomponen tersebut. Ada beberapa pendekatan berbeda untuk masalah ini. Ini yang saya suka, memiliki komponen PrivateRoute yang mengambil authedprop dan kemudian merender berdasarkan props itu.

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

Sekarang Routes Anda dapat terlihat seperti ini

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

Jika Anda masih bingung, saya menulis posting ini yang mungkin membantu - Rute terlindungi dan otentikasi dengan React Router v4

Tyler McGinnis
sumber
2
Oh ini mirip dengan solusi saya, tetapi menggunakan <Redirect />. Masalahnya adalah <Redirect />tampaknya tidak berfungsi dengan redux dalam kasus saya? Saya perlu mengirimkan tindakan
Jiew Meng
3
Saya tidak tahu mengapa, tetapi menambahkan state: {from: props.location}}}menyebabkan a maximum call stack exceeded. Saya harus menghapusnya. Bisakah Anda menjelaskan mengapa opsi ini berguna @Tyler McGinnis?
martpie
@KeIG Itu aneh. Ini berguna karena memberi tahu Anda dari mana Anda berasal. Contohnya jika Anda ingin pengguna mengautentikasi, kemudian setelah mereka mengautentikasi, bawa mereka kembali ke halaman yang mereka coba akses sebelum Anda mengarahkan mereka.
Tyler McGinnis
6
@faraz Ini menjelaskan ({component: Component, ...rest})sintaks. Saya punya pertanyaan yang sama lol! stackoverflow.com/a/43484565/6502003
protoEvangelion
2
@TylerMcGinnis Bagaimana jika kita perlu menggunakan fungsi render untuk meneruskan props ke komponen?
C Bauer
16

Tnx Tyler McGinnis untuk solusinya. Saya membuat ide saya dari ide Tyler McGinnis.

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

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

Anda dapat menerapkannya seperti ini

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

decisionFunc hanya sebuah fungsi yang mengembalikan true atau false

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

(Menggunakan Redux untuk manajemen negara)

Jika pengguna mencoba mengakses url apa pun, pertama-tama saya akan memeriksa apakah token akses tersedia, jika tidak dialihkan ke halaman login, Setelah pengguna masuk menggunakan halaman login, kami menyimpannya di penyimpanan lokal dan juga di status redux kami. (penyimpanan lokal atau cookie..kami merahasiakan topik ini dari konteksnya untuk saat ini).
karena status redux sebagai diperbarui dan privateroutes akan dirender. sekarang kami memiliki token akses sehingga kami akan mengarahkan ke halaman beranda.

Simpan juga data payload otorisasi yang didekode dalam status redux dan teruskan ke konteks reaksi. (Kami tidak harus menggunakan konteks tetapi untuk mengakses otorisasi di salah satu komponen turunan bersarang kami, ini memudahkan akses dari konteks alih-alih menghubungkan setiap komponen turunan ke redux) ..

Semua rute yang tidak memerlukan peran khusus dapat diakses langsung setelah login .. Jika membutuhkan peran seperti admin (kami membuat rute yang dilindungi yang memeriksa apakah dia memiliki peran yang diinginkan jika tidak dialihkan ke komponen yang tidak sah)

Demikian pula di salah satu komponen Anda jika Anda harus menonaktifkan tombol atau sesuatu berdasarkan peran.

sederhana yang dapat Anda lakukan dengan cara ini

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>

Jadi bagaimana jika pengguna mencoba memasukkan token dummy di penyimpanan lokal. Karena kami memiliki token akses, kami akan mengarahkan ke komponen rumah. Komponen rumah saya akan membuat panggilan istirahat untuk mengambil data, karena token jwt adalah dummy, panggilan istirahat akan mengembalikan pengguna yang tidak sah. Jadi saya memanggil logout (yang akan menghapus penyimpanan lokal dan mengarahkan ke halaman login lagi). Jika halaman beranda memiliki data statis dan tidak melakukan panggilan api apa pun (maka Anda harus memiliki panggilan api verifikasi-token di backend sehingga Anda dapat memeriksa apakah token itu NYATA sebelum memuat halaman beranda)

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

CONTOH JWT TOKEN DEKODASI

{
  "authorization": {
    "roles": [
      "admin",
      "operator"
    ]
  },
  "exp": 1591733170,
  "user_id": 1,
  "orig_iat": 1591646770,
  "email": "hemanthvrm@stackoverflow",
  "username": "hemanthvrm"
}
Hemanthvrm
sumber
Dan bagaimana Anda menangani akses langsung Signin? Jika pengguna tahu dia tidak masuk, dia seharusnya memiliki opsi untuk langsung mengakses Masuk, bukan?
carkod
@carkod ... Secara default jika dia mencoba mengakses rute mana pun, dia akan diarahkan ke halaman masuk ... (karena dia tidak akan memiliki token)
Hemanthvrm
@carkod .. setelah pengguna mengklik logout atau token refresh jwt saya kedaluwarsa .. saya melakukan fungsi logout di mana saya menghapus penyimpanan lokal dan jendela refresh ... maka penyimpanan lokal tidak akan memiliki token..itu akan secara otomatis dialihkan ke halaman login
Hemanthvrm
saya memiliki versi yang lebih baik untuk mereka yang menggunakan redux..akan memperbarui jawaban saya dalam beberapa hari..terima kasih -
Hemanthvrm
3

instal react-router-dom

lalu buat dua komponen, satu untuk pengguna valid dan lainnya untuk pengguna tidak valid.

coba ini di 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
sumber
4
Per rute? Ini tidak akan skala.
Jim G.
3

Berdasarkan jawaban dari @Tyler McGinnis . Saya membuat pendekatan berbeda menggunakan sintaks ES6 dan rute bersarang dengan komponen yang dibungkus:

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

Dan menggunakannya:

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

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

Saya tahu ini sudah lama tetapi saya telah mengerjakan paket npm untuk rute pribadi dan umum.

Berikut cara membuat rute pribadi:

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

Dan Anda juga dapat membuat rute Umum yang hanya dapat diakses oleh pengguna yang tidak sah

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

Saya harap ini membantu!

Gonzalo Cañada
sumber
dapatkah Anda memberikan lebih banyak contoh termasuk semua impor dan pembungkus, misalnya dalam 2 rute publik, 2 rute pribadi dan 2 PropsRoute, di App.js utama? terima kasih
MH
2

Saya menerapkan menggunakan-

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

alat peraga otentikasi akan diteruskan ke komponen misalnya pendaftaran menggunakan status pengguna mana yang dapat diubah. AppRoutes lengkap-

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

Periksa proyek lengkapnya di sini: https://github.com/varunon9/hello-react

Varun Kumar
sumber
1

Tampaknya ragu-ragu Anda dalam membuat komponen Anda sendiri dan kemudian mengirimkannya ke metode render? Anda bisa menghindari keduanya dengan hanya menggunakan rendermetode <Route>komponen. Tidak perlu membuat <AuthenticatedRoute>komponen kecuali Anda benar-benar menginginkannya. Ini bisa sesederhana di bawah ini. Perhatikan {...routeProps}penyebarannya dengan memastikan Anda terus mengirim properti <Route>komponen ke komponen anak ( <MyComponent>dalam kasus ini).

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

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

} />

Lihat dokumentasi render React Router V4

Jika Anda memang ingin membuat komponen khusus, sepertinya Anda berada di jalur yang benar. Karena React Router V4 adalah perutean deklaratif murni (dikatakan begitu tepat dalam deskripsi) saya rasa Anda tidak akan lolos dengan meletakkan kode pengalihan di luar siklus hidup komponen normal. Melihat kode untuk React Router itu sendiri , mereka melakukan pengalihan di salah satu componentWillMountatau componentDidMounttergantung pada apakah itu rendering sisi server atau tidak. Berikut adalah kode di bawah ini, yang cukup sederhana dan mungkin membantu Anda merasa lebih nyaman dengan tempat meletakkan logika pengalihan Anda.

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
sumber
1

Jawaban saya sebelumnya tidak dapat diskalakan. Inilah yang menurut saya pendekatan yang baik-

Rute Anda-

<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>

Idenya adalah menggunakan pembungkus dalam componentprops yang akan mengembalikan komponen asli jika tidak ada auth diperlukan atau sudah diautentikasi jika tidak akan mengembalikan komponen default misalnya 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
sumber
jika otentikasi tidak diperlukan maka jangan meneruskan komponen ke fungsi matchStateToProps, dengan itu Anda akan menghilangkan kebutuhan akan flag routeOpen
Dheeraj
1

Berikut adalah rute sederhana yang dilindungi dan bersih

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 adalah panggilan metode untuk memeriksa token otorisasi yang pada dasarnya mengembalikan boolean.

Anupam Maurya
sumber
Ini adalah satu-satunya solusi di sini yang saya temukan berfungsi jika Anda melewati Komponen atau Anak ke rute.
Shawn
Catatan: Saya baru saja memanggil isTokenVerified () di fungsi ProtectedRoute saya dan saya tidak perlu meneruskan prop isAllowed di semua rute.
Shawn
1

Inilah cara saya menyelesaikannya dengan React dan Typecript. Semoga membantu!

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
sumber
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>
  )
}
Fellow Stranger
sumber
0

Saya juga mencari jawaban. Di sini semua jawaban cukup bagus, tetapi tidak ada yang memberikan jawaban bagaimana kami dapat menggunakannya jika pengguna memulai aplikasi setelah membukanya kembali. (Maksud saya menggunakan cookie bersama-sama).

Tidak perlu membuat Komponen privateRoute yang berbeda. Di bawah ini adalah kode saya

    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;

Dan inilah 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)
}

Di bawah saya telah menulis blog, Anda juga bisa mendapatkan penjelasan yang lebih mendalam di sana.

Buat rute yang dilindungi di ReactJS

nirmal
sumber
0

Solusi yang pada akhirnya bekerja paling baik untuk organisasi saya dirinci di bawah ini, itu hanya menambahkan pemeriksaan pada render untuk rute sysadmin dan mengarahkan pengguna ke jalur utama aplikasi yang berbeda jika mereka tidak diizinkan untuk berada di halaman.

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} />);
}

Ada 3 rute utama untuk implementasi kami, publik / situs, klien / aplikasi yang masuk, dan alat admin sys di / sysadmin. Anda dialihkan berdasarkan 'keaslian' Anda dan ini adalah halaman di / sysadmin.

SysAdminNav.tsx

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