Làm cách nào để triển khai các tuyến đã xác thực trong React Router 4?


121

Tôi đã cố gắng thực hiện các tuyến xác thực nhưng thấy rằng React Router 4 hiện ngăn điều này hoạt động:

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

Lỗi là:

Cảnh báo: Bạn không nên sử dụng <Route component><Route children>trong cùng một tuyến đường; <Route children>sẽ bị bỏ qua

Trong trường hợp đó, cách chính xác để thực hiện điều này là gì?

Nó xuất hiện trong react-router(v4) tài liệu, nó gợi ý một cái gì đó như

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

Nhưng liệu có thể đạt được điều này trong khi nhóm một loạt các tuyến đường với nhau?


CẬP NHẬT

Ok, sau một số nghiên cứu, tôi đã đưa ra điều này:

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
}

Isit chính xác để gửi một hành động trong render()đó cảm thấy sai. Nó không thực sự có vẻ đúng với componentDidMounthoặc một số hook khác?


tốt nhất nên thực hiện trên PartetWillMount nếu không sử dụng kết xuất phía máy chủ.
mfahadi

@mfahadi, cảm ơn bạn đã đóng góp. Tôi chưa sử dụng SSR, nhưng nếu tôi muốn sử dụng trong tương lai, tôi có giữ nó trong kết xuất không? Ngoài ra, nếu người dùng được chuyển hướng vào componentWillMount, họ có bao giờ thấy đầu ra được kết xuất ngay cả trong một giây không?
Jiew Meng

Tôi thực sự xin lỗi vì đã nói rằng componentWillMount()nó không được gọi trên SSR, nó componentDidMount()không được gọi. như componentWillMount()được gọi trước đây render(), vì vậy người dùng sẽ không thấy bất cứ thứ gì của thành phần mới. Vì vậy, nó là nơi tốt nhất để kiểm tra.
mfahadi

1
bạn chỉ có thể sử dụng <Redirect to="/auth"> từ các tài liệu thay vì gọi hành động điều phối
Fuzail l'Corder

Câu trả lời:


238

Bạn sẽ muốn sử dụng Redirectthành phần. Có một vài cách tiếp cận khác nhau cho vấn đề này. Đây là một cái tôi thích, có một thành phần PrivateRoute có một chỗ autheddựa và sau đó kết xuất lại dựa trên các đạo cụ đó.

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

Bây giờ Routes của bạn có thể trông giống như thế này

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

Nếu bạn vẫn còn bối rối, tôi đã viết bài đăng này có thể giúp - Xác thực tuyến đường và xác thực với Bộ định tuyến React v4


2
Oh này tương tự như giải pháp của tôi, nhưng nó sử dụng <Redirect />. Vấn đề là <Redirect />dường như không hoạt động với redux trong trường hợp của tôi? Tôi cần phải gửi một hành động
Jiew Meng

3
Tôi không biết tại sao, nhưng thêm state: {from: props.location}}}gây ra a maximum call stack exceeded. Tôi đã phải loại bỏ nó. Bạn có thể giải thích tại sao tùy chọn này hữu ích @Tyler McGinnis?
martpie

@KeitIG ​​Thật lạ. Nó hữu ích vì nó cho bạn biết bạn đến từ đâu. Một ví dụ sẽ là nếu bạn muốn người dùng xác thực sau đó khi họ xác thực, hãy đưa họ trở lại trang họ đang cố truy cập trước khi bạn chuyển hướng họ.
Tyler McGinnis

6
@faraz Điều này giải thích ({component: Component, ...rest})cú pháp. Tôi đã có cùng một câu hỏi lol! stackoverflow.com/a/43484565/6502003
protoEveachion

2
@TylerMcGinnis Nếu chúng ta cần sử dụng chức năng kết xuất để truyền đạo cụ cho thành phần thì sao?
C Bauer

16

Tnx Tyler McGinnis cho giải pháp. Tôi thực hiện ý tưởng của mình từ ý tưởng của Tyler McGinnis.

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

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

Bạn có thể thực hiện như thế này

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

quyết định chỉ là một hàm trả về đúng hay sai

const redirectStart = props => <Redirect to="/orders" />

8

(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"
}

Và làm thế nào để bạn xử lý truy cập trực tiếp đến Signin? Nếu người dùng biết anh ta chưa đăng nhập, anh ta nên có tùy chọn truy cập trực tiếp vào Signin, phải không?
carkod

@carkod ... Theo mặc định, nếu anh ta cố gắng truy cập bất kỳ tuyến đường nào, anh ta sẽ được chuyển hướng đến trang đăng nhập ... (vì anh ta sẽ không có mã thông báo)
Hemanthvrm

@carkod .. khi người dùng nhấp vào logout hoặc nếu không tôi JWT làm mới thẻ hết hạn ..Tôi làm chức năng logout gọi nơi tôi rõ ràng localStorage và cửa sổ làm mới ... do đó localStorage sẽ không được có token..it sẽ automaticaly chuyển hướng đến trang đăng nhập
Hemanthvrm

tôi có phiên bản tốt hơn cho những người sử dụng redux..sẽ cập nhật câu trả lời của tôi sau vài ngày..cảm ơn -
Hemanthvrm

3

cài đặt Reac-router-dom

sau đó tạo hai thành phần một cho người dùng hợp lệ và thành phần khác cho người dùng không hợp lệ.

thử cái này trên 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;

4
Mỗi tuyến? Điều này sẽ không quy mô.
Jim G.

3

Dựa trên câu trả lời của @Tyler McGinnis . Tôi đã thực hiện một cách tiếp cận khác bằng cách sử dụng cú pháp ES6các tuyến được lồng với các thành phần được bọc:

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

Và sử dụng nó:

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

    <Route exact path='/' component={PublicHomePage} />
  </div>
</BrowserRouter>

2

Tôi biết đã được một thời gian nhưng tôi đã làm việc trên gói npm cho các tuyến riêng và công cộng.

Đây là cách tạo lộ trình riêng tư:

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

Và bạn cũng có thể tạo các tuyến công cộng mà chỉ người dùng chưa được xác thực mới có thể truy cập

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

Tôi hy vọng nó sẽ giúp!


bạn có thể vui lòng cung cấp thêm ví dụ bao gồm tất cả các lần nhập và kết thúc, ví dụ như trong 2 công khai, 2 tuyến riêng và 2 propsRoute, trong App.js chính không? cảm ơn bạn
MH

2

Tôi đã thực hiện bằng cách sử dụng-

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

đạo cụ xác thực sẽ được chuyển đến các thành phần, ví dụ như đăng ký bằng cách sử dụng trạng thái người dùng có thể được thay đổi. Hoàn thành xuất hiện-

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

Kiểm tra dự án hoàn chỉnh tại đây: https://github.com/varunon9/hello-react


1

Có vẻ như sự do dự của bạn là trong việc tạo thành phần của riêng bạn và sau đó gửi đi trong phương thức kết xuất? Vâng, bạn có thể tránh cả hai chỉ bằng cách sử dụng renderphương pháp của <Route>thành phần. Không cần phải tạo một <AuthenticatedRoute>thành phần trừ khi bạn thực sự muốn. Nó có thể đơn giản như dưới đây. Lưu ý sự {...routeProps}lây lan đảm bảo rằng bạn tiếp tục gửi các thuộc tính của <Route>thành phần xuống thành phần con ( <MyComponent>trong trường hợp này).

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

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

} />

Xem tài liệu kết xuất React Router V4

Nếu bạn đã muốn tạo một thành phần chuyên dụng, thì có vẻ như bạn đang đi đúng hướng. Vì React Router V4 hoàn toàn là định tuyến khai báo (nó nói rất đúng trong mô tả) Tôi không nghĩ bạn sẽ thoát khỏi việc đưa mã chuyển hướng của bạn ra ngoài vòng đời thành phần thông thường. Nhìn vào mã cho chính React Router , họ thực hiện chuyển hướng theo một trong hai componentWillMounthoặc componentDidMounttùy thuộc vào việc nó có hiển thị phía máy chủ hay không. Đây là đoạn mã dưới đây, khá đơn giản và có thể giúp bạn cảm thấy thoải mái hơn với nơi đặt logic chuyển hướng của mình.

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

1

Câu trả lời trước của tôi không thể mở rộng. Đây là những gì tôi nghĩ là cách tiếp cận tốt-

Tuyến đường của bạn-

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

Ý tưởng là sử dụng một trình bao bọc trong các componentđạo cụ sẽ trả về thành phần gốc nếu không yêu cầu xác thực hoặc đã được xác thực nếu không sẽ trả về thành phần mặc định, ví dụ Đăng nhập.

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

nếu không cần xác thực thì không chuyển thành phần cho hàm matchStateToProps, với điều đó bạn sẽ loại bỏ nhu cầu về cờ routeOpen
Dheeraj

1

Đây là tuyến đường được bảo vệ sạch sẽ đơn giản

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 là một cuộc gọi phương thức để kiểm tra mã thông báo ủy quyền về cơ bản, nó trả về boolean.


Đây là giải pháp duy nhất ở đây tôi thấy có hiệu quả nếu bạn chuyển một Thành phần hoặc Trẻ em đến tuyến đường.
Shawn

Lưu ý: Tôi vừa gọi isToken Tweet () trong funciton ProtectedRoute của tôi và tôi không cần phải vượt qua prop isowowed trên tất cả các tuyến.
Shawn

1

Đây là cách tôi giải quyết nó với React và Typecript. Hy vọng nó giúp !

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


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

0

Tôi cũng đang tìm kiếm một số câu trả lời. Ở đây tất cả các câu trả lời đều khá tốt, nhưng không ai trong số họ đưa ra câu trả lời về cách chúng tôi có thể sử dụng nó nếu người dùng khởi động ứng dụng sau khi mở lại. (Tôi muốn nói là sử dụng cookie cùng nhau).

Không cần phải tạo thành phần PrivateRoute khác nhau. Dưới đây là mã của tôi

    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;

Và đây là 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)
}

Dưới đây tôi đã viết blog, bạn cũng có thể giải thích sâu hơn.

Tạo các tuyến được bảo vệ trong ReactJS


0

Giải pháp cuối cùng hoạt động tốt nhất cho tổ chức của tôi được trình bày chi tiết bên dưới, nó chỉ thêm một kiểm tra kết xuất cho tuyến đường sysadmin và chuyển hướng người dùng đến một đường dẫn chính khác của ứng dụng nếu họ không được phép vào trang.

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

Có 3 tuyến đường chính để triển khai của chúng tôi, đối mặt với công chúng / trang web, ứng dụng khách / ứng dụng đã đăng nhập và các công cụ quản trị hệ thống tại / sysadmin. Bạn được chuyển hướng dựa trên 'quyền tác giả' của bạn và đây là trang tại / sysadmin.

SysAdminNav.tsx

<Switch>
    <SysAdminRoute exact path={sysadminUrls.someSysAdminUrl} render={() => <SomeSysAdminUrl/> } />
    //etc
</Switch>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.