react-router에서 경로에 대한 액세스를 제한하는 방법은 무엇입니까?


83

누구든지 react-router에서 특정 경로에 대한 액세스를 제한하는 방법을 알고 있습니까? 특정 경로에 대한 액세스를 허용하기 전에 사용자가 로그인했는지 확인하고 싶습니다. 간단 할 거라고 생각했지만 문서에 방법이 명확하지 않습니다.

<Route>구성 요소를 정의 할 때 설정 해야합니까, 아니면 구성 요소 처리기 내에서 처리해야합니까?

<Route handler={App} path="/">
  <NotFoundRoute handler={NotFound} name="not-found"/>
  <DefaultRoute handler={Login} name="login"/>
  <Route handler={Todos} name="todos"/> {/* I want this to be restricted */}
</Route>

로그인되지 않은 경우 로그인 처리기로 리디렉션합니다. 또한 클라이언트는로드하는 모든 JS에 액세스 할 수 있으므로 민감한 정보를 저장하지 마십시오.
Thirty Two 대령

@Tanner Semerad는 이것을 어떻게 간단히 달성했는지에 대한 github 저장소를 가지고 있습니까?
jit

@jit, 죄송합니다. 아래 miciek의 대답은 내가 필요로하는 것이었지만 이것은 react-router 1.0 이전 버전이라는 것을 명심하십시오. 1.0이 출시 된 이후로 많은 것이 변경된 것을 알고 있지만 거의 비슷합니다.
Tanner Semerad

@ jayair의 대답은 내가 지금 사용하고 무엇이며, 그것은 잘 작동
태너 Semerad

답변:


94

업데이트 (2019 년 8 월 16 일)

react-router v4에서 React Hooks를 사용하면 약간 다르게 보입니다. 의 당신의 시작하자 App.js.

export default function App() {
  const [isAuthenticated, userHasAuthenticated] = useState(false);

  useEffect(() => {
    onLoad();
  }, []);

  async function onLoad() {
    try {
      await Auth.currentSession();
      userHasAuthenticated(true);
    } catch (e) {
      alert(e);
    }
  }

  return (
    <div className="App container">
      <h1>Welcome to my app</h1>
      <Switch>
        <UnauthenticatedRoute
          path="/login"
          component={Login}
          appProps={{ isAuthenticated }}
        />
        <AuthenticatedRoute
          path="/todos"
          component={Todos}
          appProps={{ isAuthenticated }}
        />
        <Route component={NotFound} />
      </Switch>
    </div>
  );
}

Auth사용자가 현재 인증되었는지 확인하기 위해 라이브러리를 사용하고 있습니다. 이것을 인증 확인 기능으로 대체하십시오. 그렇다면 isAuthenticated플래그를로 설정합니다 true. 앱이 처음로드 될 때이 작업을 수행합니다. 또한 언급 할 가치가있는 것은 인증 확인이 실행되는 동안 앱에로드 기호를 추가 할 수 있으므로 페이지를 새로 고칠 때마다 로그인 페이지를 플래시하지 않습니다.

그런 다음 깃발을 경로에 전달합니다. 두 가지 유형의 경로 AuthenticatedRouteUnauthenticatedRoute.

AuthenticatedRoute.js모습이 맘에.

export default function AuthenticatedRoute({ component: C, appProps, ...rest }) {
  return (
    <Route
      {...rest}
      render={props =>
        appProps.isAuthenticated
          ? <C {...props} {...appProps} />
          : <Redirect
              to={`/login?redirect=${props.location.pathname}${props.location.search}`}
            />}
    />
  );
}

가로 isAuthenticated설정되어 있는지 확인합니다 true. 그렇다면 원하는 구성 요소를 렌더링합니다. 그렇지 않은 경우 로그인 페이지로 리디렉션됩니다.

UnauthenticatedRoute.js다른 한편으로는 다음과 같습니다.

export default ({ component: C, appProps, ...rest }) =>
  <Route
    {...rest}
    render={props =>
      !appProps.isAuthenticated
        ? <C {...props} {...appProps} />
        : <Redirect to="/" />}
  />;

이 경우 isAuthenticated가로 설정되어 있으면 false원하는 구성 요소를 렌더링합니다. true로 설정하면 홈페이지로 이동합니다.

자세한 버전은 당사 가이드 ( https://serverless-stack.com/chapters/create-a-route-that-redirects.html) 에서 찾을 수 있습니다 .

이전 버전

허용되는 답변은 맞지만 Mixins는 React 팀에 의해 유해한 것으로 간주됩니다 ( https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html ).

누군가이 질문을 발견하고 권장되는 방법을 찾고 있다면 Mixins 대신 Higher Order Components를 사용하는 것이 좋습니다.

다음은 계속하기 전에 사용자가 로그인했는지 확인하는 HOC의 예입니다. 사용자가 로그인하지 않은 경우 로그인 페이지로 리디렉션됩니다. 이 구성 요소 isLoggedIn는 기본적으로 사용자가 로그인했는지 여부를 나타 내기 위해 응용 프로그램에서 저장할 수있는 플래그 인 라는 prop을받습니다 .

import React from 'react';
import { withRouter } from 'react-router';

export default function requireAuth(Component) {

  class AuthenticatedComponent extends React.Component {

    componentWillMount() {
      this.checkAuth();
    }

    checkAuth() {
      if ( ! this.props.isLoggedIn) {
        const location = this.props.location;
        const redirect = location.pathname + location.search;

        this.props.router.push(`/login?redirect=${redirect}`);
      }
    }

    render() {
      return this.props.isLoggedIn
        ? <Component { ...this.props } />
        : null;
    }

  }

  return withRouter(AuthenticatedComponent);
}

그리고이 HOC를 사용하려면 경로를 감싸십시오. 귀하의 예의 경우 다음과 같습니다.

<Route handler={requireAuth(Todos)} name="todos"/>

여기에있는 자세한 단계별 자습서 ( https://serverless-stack.com/chapters/create-a-hoc-that-checks-auth.html) 에서이 항목과 몇 가지 다른 주제를 다룹니다.


원래 코드가 <Route getComponent = {myAsyncComponentGenerator}>를 사용하고 있었다면이 예제에서 어떻게 작동하도록 만들 수 있습니까?
Bran

나는 매우 유사한 코드를 가지고 있지만 내 질문은 충분히 안전합니까? I 공격자가 교체되도록 JS 축소 된 코드가 변경 될 수 평균 this.props.isLoggedIn으로 true우회 로그인?
karim elhelawy

4
@karimelhelawy 사실이며 서버의 API에서 인증을 시행해야하기 때문입니다.
cbr

7
<Route handler={}/>v1.0에서 더 이상 사용되지 않으므로 <Route component={} />.
Knowledge

1
componentWillMount곧 지원이 중단됩니다. reactjs.org의 블로그 게시물에서 읽어보세요 . 대신 @jacob가 제공 한 대답으로 갈 것입니다.
Tom

29

React Router 4의 문서에 이에 대한 예가 있습니다. Redirect

import { Route, Redirect } from 'react-router'

<Route exact path="/" render={() => (
  loggedIn ? (
    <Redirect to="/dashboard"/>
  ) : (
    <PublicHomePage/>
  )
)}/>

"loggedIn"을 함수 나 변수로 어떻게 사용할 수 있습니까?. 당신은 단지 그것을 조금 설명 할 수
Kunvar 싱에게

@KunvarSingh 값이 변경되기 때문에 아마도 함수 여야합니다.
jacob

3

react-router 라우터에 대한 선언적 접근 방식을 권장합니다. 라우터를 가능한 한 멍청하게 만들고 구성 요소에 라우팅 논리를 넣지 않도록해야합니다.

방법은 다음과 같습니다 ( loggedIn소품 을 전달한다고 가정 ).

const DumbRouter = ({ loggedIn }) => (
  <Router history={history}>
    <Switch>
      {[
        !loggedIn && LoggedOutRoutes,
        loggedIn && LoggedInRouter,
        <Route component={404Route} />
      ]}
    </Switch>
  </Router>
);

const LoggedInRoutes = [
  <Route path="/" component={Profile} />
];

const LoggedOutRoutes = [
  <Route path="/" component={Login} />
];

이것은 매우 간단합니다. 문제는 일반적으로 로그 아웃했거나 로그인 한 경우 동일한 경로를 인식하기를 원하므로 사용자가 로그 아웃 된 경우 로그인으로 올바르게 리디렉션 할 수 있습니다. 일반적으로 경로는 동일하지만 로그인 상태에 따라 다른 방식으로 작동하기를 원합니다. 또한 솔루션을 사용하면 유지 관리가 더 어려운 2 개의 다른 위치에 동일한 경로를 만들어 중복을 추가합니다.
Rafael Porras Lucena

2

전체 애플리케이션에서 인증을 사용하려면 애플리케이션 전체에 일부 데이터 (예 : 토큰)를 저장해야합니다. $auth객체 관리를 담당하는 두 개의 React mixin을 설정할 수 있습니다 . 이 개체는 두 믹스 인 외부에서 사용할 수 없습니다. 그 예는 다음과 같습니다.

define('userManagement', function() {
    'use strict';

    var $auth = {
        isLoggedIn: function () {
            // return something, e.g. using server-stored data
        }
    };

    return {
        Authenticator: {
           login: function(username, password) {
               // modify $auth object, or call server, or both
           }
        },

        NeedsAuthenticatedUser: {
            statics: {
                willTransitionTo: function (transition) {
                    if (!$auth.isLoggedIn()) {
                        transition.abort();
                    }
                }
            }
        }
    };
});

그런 다음 Authenticator로그인 구성 요소 (로그인 화면, 로그인 팝업 등)에 믹싱을 혼합하고 this.login필요한 모든 데이터가 있으면 함수를 호출 할 수 있습니다.

가장 중요한 것은 NeedsAuthenticatedUsermixin 을 혼합하여 구성 요소를 보호하는 것입니다 . 인증 된 사용자가 필요한 각 구성 요소는 다음과 같아야합니다.

var um = require('userManagement');

var ProtectedComponent = React.createClass({
    mixins: [um.NeedsAuthenticatedUser]
    // ...
}

하는 것으로 NeedsAuthenticatedUser사용이 반응 라우터의 API ( willTransitionTotransition.abort()).


2
믹스 인은 계속 진행하는 것이 좋지 않습니다. 더 읽기
boldnik


1
믹스 인은 ES6에서 제거되었으며 React는 더 이상 사용하지 않습니다.
Pier

1

HOC를 사용할 수 있으며 auth는 true 또는 false 값을 변경할 수있는 변수입니다 (권한 부여).

<Route path="/login" component={SignIn} />
<Route path="/posts" render = {() => (auth ?  (<Post />) : (<Redirect to="/login" />))}/>

0

private-route.tsx

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

interface PrivateRouteProps extends RouteProps {
  /**
   * '/login' for example.
   */
  redirectTo: string;

  /**
   * If true, won't redirect.
   * We are using a function instead of a bool, a bool does not seem to be updated
   * after having successfully authenticated.
   */
  isLogged: () => boolean;
}


export function PrivateRoute(props: PrivateRouteProps) {
  // `component: Component` is not typing, it assign the value to a new variable.
  let { isLogged, redirectTo, component: Component, ...rest }: any = props;

  // error: JSX type element Component does not have call signature or ... AVOIDED BY ADDING ANY, still work,
  // and did not find a proper way to fix it.
  return <Route {...rest} render={(props) => (
    isLogged()
      ? <Component {...props}/>
      : <Redirect to={{
        pathname: redirectTo,
        state: { from: props.location }
      }} />
  )} />;
}

용법:

        <PrivateRoute exact={true} 
                      path="/admin/" 
                      redirectTo={'/admin/login'} 
                      isLogged={this.loginService.isLogged} 
                      component={AdminDashboardPage}/>
        <Route path="/admin/login/" component={AdminLoginPage}/>

https://tylermcginnis.com/react-router-protected-routes-authentication/ 기반 .


-2

일반적으로 로그인 한 사용자에게는 토큰이 부여되며 서버와의 모든 통신에이 토큰을 사용합니다. 우리가 일반적으로하는 일은 루트 페이지를 정의하는 것이며, 그 페이지 위에 모든 것이 구축됩니다. 이 루트 페이지는 현지화, 인증 및 기타 구성을 수행합니다.

여기에 예가 있습니다

Routes = (
    <Route path="/" handler={Root}>
        <Route name="login" handler={Login} />
        <Route name="forget" handler={ForgetPassword} />
        <Route handler={Main} >
            <Route name="overview" handler={Overview} />
            <Route name="profile" handler={Profile} />
            <DefaultRoute handler={Overview} />
        </Route>
        <DefaultRoute handler={Login} />
        <NotFoundRoute handler={NotFound} />
    </Route>
);

루트 페이지에서 토큰 null을 확인하거나 서버에서 토큰을 인증하여 사용자가 유효한 로그인인지 확인하십시오.

도움이 되었기를 바랍니다 :)


2
맞습니다. 인증이 완료되지 않은 경우 가져 오기 위해 "개요"클래스를 어떻게 중지 할 수 있습니까? 아니면 "기본"처리기가 ​​어떻게 생겼습니까? 예를 들어 "개요"에 인증 된 앱을 실행해야하는 종속성이있는 경우 어떻게됩니까? 라우터에서 실행하기 위해 가져 오기 때문에 모든 종속성도 가져 오므로 앱이 손상됩니까?
Marais Rossouw 2015

이 질문 한 질문에 대답하지 않습니다
HermannHH
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.