programing

로그인 여부 확인 - 리액트 라우터 애플리케이션 ES6

i4 2023. 2. 20. 23:57
반응형

로그인 여부 확인 - 리액트 라우터 애플리케이션 ES6

react-router(v2.8.1) 및 ES6 구문을 사용하여 React.js 어플리케이션(v15.3)을 작성하고 있습니다.사용자가 먼저 로그인해야 하는지 확인하기 위해 페이지 간의 모든 전환을 대행 수신하도록 라우터 코드를 가져올 수 없습니다.

나의 최상위 렌더링 방법은 매우 단순합니다(앱도 단순합니다).

 render()
   {
      return (
         <Router history={hashHistory}>
            <Route path="/" component={AppMain}>
               <Route path="login" component={Login}/>
               <Route path="logout" component={Logout}/>
               <Route path="subject" component={SubjectPanel}/>
               <Route path="all" component={NotesPanel}/>
            </Route>
         </Router>
      );
   }

웹상의 샘플은 모두 ES5 코드 또는 이전 버전의 react-router(버전 2보다 오래된 버전)를 사용하고 있으며 mixin(비권장) 및 willTransitionTo(호출되지 않음)를 사용한 다양한 시도는 실패했습니다.

사용자가 요청한 페이지에 도착하기 전에 인증을 강제하도록 글로벌 '인터셉터 기능'을 설정하려면 어떻게 해야 합니까?

모든 경로에는 경로 천이가 발생하기 전에 호출되는 onEnter 후크가 있습니다.사용자 지정 요구 사항에 따라 onEnter 후크 처리인증 기능

<Route path="/search" component={Search} onEnter={requireAuth} />

샘플에 필요한 것은인증은 다음과 같습니다.사용자가 인증되면 next()를 사용하여 이행합니다.그렇지 않으면 경로 이름을 /login으로 바꾸고 next()를 통해 전환합니다.로그인은 현재 경로명도 전달되므로 로그인 완료 후 사용자는 원래 요청된 경로로 리다이렉트됩니다.

function requireAuth(nextState, replace, next) {
  if (!authenticated) {
    replace({
      pathname: "/login",
      state: {nextPathname: nextState.location.pathname}
    });
  }
  next();
}

v4에서는 사용이 인증되었는지 확인하는 경로 구성 요소를 생성하고 다음 구성 요소를 반환하면 됩니다. 물론 다음 구성 요소는 다른 경로가 될 수 있습니다.

import React, { Component } from 'react';
import PropTypes from 'prop-types';

import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Route, Redirect } from 'react-router-dom';

import AuthMiddleware from 'modules/middlewares/AuthMiddleware';

class PrivateRoute extends Component {
  static propTypes = {
    component: PropTypes.func.isRequired,
    isAuthenticated: PropTypes.bool,
    isLoggedIn: PropTypes.func.isRequired,
    isError: PropTypes.bool.isRequired
  };

  static defaultProps = {
    isAuthenticated: false
  };

  constructor(props) {
    super(props);
    if (!props.isAuthenticated) {
      setTimeout(() => {
        props.isLoggedIn();
      }, 5);
    }
  }

  componentWillMount() {
    if (this.props.isAuthenticated) {
      console.log('authenticated');
    } else {
      console.log('not authenticated');
    }
  }
  componentWillUnmount() {}

  render() {
    const { isAuthenticated, component, isError, ...rest } = this.props;
    if (isAuthenticated !== null) {
      return (
        <Route
          {...rest}
          render={props => (
            isAuthenticated ? (
              React.createElement(component, props)
            ) : (
              <Redirect
                to={{
                  pathname: isError ? '/login' : '/welcome',
                  state: { from: props.location }
                }}
              />
            )
          )}
        />
      );
    } return null;
  }

}

const mapStateToProps = (state) => {
  return {
    isAuthenticated: state.auth.isAuthenticated,
    isError: state.auth.isError
  };
};

const mapDispatchToProps = (dispatch) => {
  return bindActionCreators({
    isLoggedIn: () => AuthMiddleware.isLoggedIn()
  }, dispatch);
};

export default connect(mapStateToProps, mapDispatchToProps)(PrivateRoute);

이 버전의 onEnter 콜백은 리액트라우터(v2.8)에 대해 동작했습니다.

 requireAuth(nextState,
               replace)
   {
      if(!this.authenticated()) // pseudocode - SYNCHRONOUS function (cannot be async without extra callback parameter to this function)
         replace('/login')
   }

V1과 v2의 리액트라우터 리다이렉션 차이를 설명하는 링크는 다음과 같습니다.관련 섹션은 다음과 같습니다.

Likewise, redirecting from an onEnter hook now also uses a location descriptor.

// v1.0.x
(nextState, replaceState) => replaceState(null, '/foo')
(nextState, replaceState) => replaceState(null, '/foo', { the: 'query' })

// v2.0.0
(nextState, replace) => replace('/foo')
(nextState, replace) => replace({ pathname: '/foo', query: { the: 'query' } })

풀코드 리스트는 다음과 같습니다(React-Router 버전 2.8.1

requireAuth(nextState,
               replace)
{
   if(!this.authenticated()) // pseudocode - SYNCHRONOUS function (cannot be async without extra callback parameter to this function)
     replace('/login');
}

render() {
  return (
     <Router history={hashHistory}>
        <Route path="/" component={AppMain}>
           <Route path="login" component={Login}/>
           <Route path="logout" component={Logout}/>
           <Route path="subject" component={SubjectPanel} onEnter={this.requireAuth}/>
           <Route path="all" component={NotesPanel} onEnter={this.requireAuth}/>
        </Route>
     </Router>
  );
}

리액트 라우터 4 이상을 사용하고 있는 경우는, 렌더 소품을 사용해 리다이렉트 해 주세요.참조: onEnter가 React-Router에서 호출되지 않음

이것은 안전한 해결책이 아니다.
로그인이 필요한 모든 페이지에서 다음과 같이 useEffect 훅을 사용할 수 있습니다.

useEffect(() => {
  const token = localStorage.getItem('token');
  if(!token) {
    history.push('/login');
  }
}

이것은 'react-router-dom'의 useHistory 훅을 사용합니다.
다음과 같이 호출하기 전에 초기화만 하면 됩니다.

const history = useHistory();

앞서 말한 바와 같이 안전한 슬로우션이 아니라 단순한 슬로우션입니다.

RestrictedRoute 또는 Private 컴포넌트를 생성하여 redex 사용자 인증 스테이트를 이 컴포넌트에 전달하고 스테이트가 false일 경우 RestrictedRoute 컴포넌트리다이렉트로 전달합니다.

코드:

const RestrictedRoute = ({ component: Component, authUser, auth, ...rest }) => (
  <Route
    {...rest}
    render={props =>
      auth.is_authenticated && auth.is_authorized && authUser ? (
        <Component {...props} />
      ) : (
        <Redirect
          to={{
            pathname: '/signin',
            state: { from: props.location },
          }}
        />
      )
    }
  />
);
<Switch>
     <RestrictedRoute path={`${match.url}app`}
       authUser={authUser}
       auth={{ is_authenticated, is_authorized }}
       component={MainApp}
     />
     <Route path='/signin' component={SignIn} />
<Switch>

언급URL : https://stackoverflow.com/questions/40055439/check-if-logged-in-react-router-app-es6

반응형