IT

React Router 4에서 인증 된 경로를 구현하는 방법은 무엇입니까?

lottoking 2020. 8. 26. 08:09
반응형

React Router 4에서 인증 된 경로를 구현하는 방법은 무엇입니까?


인증 된 경로를 구현하려고 시도했지만 React Router 4가 작동하지 않는다는 것을 알았습니다.

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

오류는 다음과 가변적입니다.

경고 : <Route component><Route children>동일한 경로에서 사용됩니다 . <Route children>무시됩니다

이 경우이를 구현하는 올바른 방법은 무엇입니까?

react-router(v4) 문서에 표시되고 다음과 같은 것을 제안합니다.

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

그러나 여러 경로를 함께 그룹화하면서 달성 할 수있는 있습니까?


최신 정보

좋아, 약간의 조사 끝에 나는 생각해 봅니다.

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
}

을 파견하는 행동 render()것이 맞습니까 ? componentDidMount또는 다른 후크가 있다는 입니다.


Redirect구성 요소 를 사용하고 싶을 것 입니다. 이 문제에 대한 몇 가지 다른 접근 방식이 있습니다. 여기 내가 좋아하는 것이 있는데, authed소품을 받아 그 소품을 구성으로하는 것이 좋습니다 .

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

이제 당신 Route은 다음과 같이 보일 수 있습니다.

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

여전히 혼란 스러우 시다면 도움이 될 수있는이 게시물을 작성했습니다.- React Router v4로 보호 된 경로 및 인증


Tnx Tyler McGinnis가 솔루션을 제공합니다. 나는 Tyler McGinnis 아이디어에서 내 아이디어를 만듭니다.

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

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

다음과 같이 구현할 수 있습니다.

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

DecisionFunc는 true 또는 false를 반환하는 함수입니다.

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

react-router-dom 설치

그런 다음 유효한 사용자 용과 유효하지 않은 사용자 용으로 두 개의 구성 요소를 만듭니다.

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;

문제에 내 솔루션을 추가하는 것뿐입니다.

인증을 위해 jwt 토큰을 사용하고 있으므로 사용자가 해당 토큰을 가지고 있습니다. 홈페이지로 리디렉션하거나 기본적으로 로그인 페이지 (이 경로 '/')로 리디렉션합니다. 따라서 사용자가 로그인하고 로그인 페이지 URL (내 경우에는 '/')에 액세스하려고합니다. 기본적으로 홈 ( '/ home')으로 리디렉션합니다.

내 구성 요소에는 사용자 토큰이 유효한지 확인하기 위해 requireAuth라는 HOC가 있습니다. 라이선스 localhistory 토큰을 제거하는 사인 아웃 작업을 호출합니다.

import React, { Component, Fragment } from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch, Redirect  } from 'react-router-dom';  

//and also import appropriate components

//middleware

  class checkStatus extends React.Component {
        render() {
              if(localStorage.getItem('token')){
                return (
                  <Fragment>
                    <App>
                      <Route path="/home" exact component={Overview} />
                      <Route path="/home/add" exact component={Add} />
                      <Route path="/signout" component={Signout} />
                      <Route path="/details" component={details} />
                      <Route exact path="/" render={() => <Redirect to="/home" />} />
                    </App>

                </Fragment>
                )
              }else{
                return (
                  <Fragment>
                    <Route path="/" exact component={Signin} />
                    <Redirect to="/"  />
                  </Fragment>
                )
              }
         } }

    ReactDOM.render(   <Provider store={store}>
        <BrowserRouter>
          <Switch >
              <Route path="/" exact component={checkStatus} />
              <Route path="/:someParam"  component={checkStatus}/>
          </Switch >
        </BrowserRouter>   </Provider>,   document.querySelector('#root')
);

오랜만 이라는 이름을 갖고 싶다는 개인 및 공용 경로를 npm 패키지 작업을 해위 한 것 입니다.

비공개 경로를 만드는 방법은 다음과 가변적입니다.

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

또한 인증되지 않은 사용자 만 액세스 할 수있는 공개 경로를 만들 수도 있습니다.

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

도움이 되셨기를 바랍니다.


@Tyler McGinnis 의 답변을 기반으로합니다 . ES6 구문래핑 된 구성 요소가있는 중첩 경로사용하여 다른 접근 방식을 만들었습니다 .

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

그리고 그것을 사용 :

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

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

자신의 구성 요소를 만든 다음 방법에서 디스패치하는 데 주저하는 것입니다. 구성 요소 render방법을 사용하여 둘 다 피할 수 있습니다 <Route>. <AuthenticatedRoute>활동하지 않는 구성 요소 를 만들 필요가 없습니다 . 아래와 같이 간단하게 할 수 있습니다. 메모 {...routeProps}당신이의 속성 보내 계속 조사 결정을 <Route>(하위 구성 요소에 대한 구성 요소 아래로이 경우 <MyComponent>에는).

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

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

} />

React Router V4 문서를 참조하세요.

전용 구성 요소를 만들고 싶었다면 올바른 방향으로 가고있는 것입니다. React Router V4는 순전히 선언적 라우팅 이기 때문에 (설명에서 그렇게 말하고 있습니다) 구성 요소 수명주기 외부에서 리디렉션 코드를 두는 벗어나지 않을 것을 생각합니다. 상기 라우터 자체에 대한 코드 반응 , 그들이 수신에서 리디렉션을 수행에 따라 componentWillMount또는 서버에서 리디렉션을 수행 componentDidMount합니다. 아래 코드는 매우 간단하며 리디렉션을 어디에 배치 해야하는지 더 편안하게 느끼는 데 도움이 될 수 있습니다.

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

나는 사용하여 구현했다.

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

인증 소품은 구성 요소에 전달됩니다 (예 : 사용자 상태를 설명 수있는 등록). 완전한 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>
        );
    }
} 

여기에서 전체 프로젝트를 확인하십시오 : https://github.com/varunon9/hello-react


내 이전 답변은 확장 가능하지 않습니다. 여기에 좋은 접근 방식이라고 생각합니다.

귀하의 경로

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

아이디어는 component인증이 필요하지 않으면 이미 인증 된 경우 원래 구성 요소를 반환하는 소품에 래퍼를 사용하는 것입니다. 텍스트 로그인과 같은 기본 구성 요소를 반환합니다.

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

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

다음은 간단하고 고유 한 보호 경로입니다.

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인증 토큰을 확인하는 메서드 호출입니다. 기본적으로 부울을 반환합니다.


나는 또한 몇 가지 대답을 찾았습니다. 여기에 모든 답변이 꽤 좋지만 사용자가 다시 연 후 응용 프로그램을 시작하면 사용할 수있는 방법에 대한 답변은 없습니다. (쿠키를 함께 사용하는 것을 의미했습니다).

다른 privateRoute 구성 요소도 만들 필요가 없습니다. 아래는 내 코드입니다.

    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;

그리고 여기 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)
}

아래에서 블로그를 작성했습니다. 거기에 더 자세한 설명을 얻을 수 있습니다.

ReactJS에서 보호 경로 만들기

참고 URL : https://stackoverflow.com/questions/43164554/how-to-implement-authenticated-routes-in-react-router-4

반응형