Частная и общедоступная c аутентификация на основе маршрутов с избыточностью, работающей не так, как задумано - PullRequest
0 голосов
/ 28 марта 2020

Я пытаюсь реализовать частные, защищенные и публичные c маршруты для проекта, над которым я работаю. На каждой странице refre sh я отправляю своего создателя действия setUserAsyn c () в componentDidMount в моем приложении. js, который вызывает мой бэкэнд и запрашивает информацию о пользователе на основе токена, назначенного при входе в систему или регистрации. SetUserAsyn c устанавливает пользователя и переключает состояние isAuthenticated в true, если пользователь принят. Затем я использую состояние isAuthenticated, чтобы определить, какой компонент следует рендерить или перенаправлять в моих личных и опубликованных маршрутах c.

Но проблема, с которой я сталкиваюсь, заключается в том, что всякий раз, когда я пытаюсь получить доступ к какому-либо частному или защищенному маршруту, троичный оператор немедленно запускается на основе начального состояния isAuthenticated, которое является ложным. Следовательно, на частном маршруте, таком как / dashboard, я перейду в / signin, поскольку isAuthenticated изначально имеет значение false до тех пор, пока setUserAsyn c () в componentDidMount приложения не установит значение true. js. Затем из / signin я перенаправлен обратно на / dashboard, так как / signin является защищенным маршрутом и возвращает меня к / dashboard, так как isAuthenticated к тому времени наконец становится истинным.

Как я могу сделать так, чтобы мои маршруты на refre sh дождитесь завершения вызова API, прежде чем что-либо делать. Я видел, как многие люди применяют один и тот же поток, и он прекрасно работает для них, но я не знаю, что я делаю неправильно.

//App.js

class App extends React.Component {

componentDidMount() {
const { setUserAsync, token, tokenExpiry } = this.props;
token ? setUserAsync(token) : null
}
 render() {
  return (
  <Switch>
    <PublicRoute exact path="/" component={Home} />
    <PublicRoute exact path="/about-us" component={AboutUs} />
    <PublicRoute exact path="/contact-us" component={ContactUs} />
    <PublicRoute exact path="/privacy-policy" component={PrivacyPolicy} />
    <PublicRoute exact path="/terms-of-use" component={TermsOfUse} />

    <ProtectedRoute exact path="/signin" component={SignIn} />
    <ProtectedRoute exact path="/signup" component={SignUp} />

    <PrivateRoute exact path="/dashboard" component={Dashboard} />
    <PrivateRoute exact path="/all-leads" component={AllLeads} />
   </Switch>
 )};

const mapStateToProps = createStructuredSelector({
 token: selectUserToken,
 tokenexpiry: selectTokenExpiry
});

const mapDispatchToProps = dispatch => ({
 setUserAsync: (token) => dispatch(setUserAsync(token))
});

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




//PrivateRoute - dashboard
const PrivateRoute = ({ component: Component,isAuthenticated, ...rest }) => {
  return (
    <Route
      {...rest}
   render={props =>
     isAuthenticated ? (
       <Component {...props} />
     ) : (
       <Redirect
         to={{ pathname: "/signin", state: { from: props.location } }}
       />
     )
    }
  />
 ) 
};

const mapStateToProps = createStructuredSelector({
  isAuthenticated: selectIsUserAuthenticated,
});

export default connect(mapStateToProps)(PrivateRoute);


//ProtectedRoute - signin & signup
const ProtectedRoute = ({component: Component, isAuthenticated, isFetching, ...rest}) => {
    return !isFetching ? (
     <Route
      {...rest}
    render={(props) => 
      isAuthenticated
      ? <Redirect to={{pathname: '/dashboard', state: {from: props.location}}} />
      : <Component {...props} /> }
   />
  )
  : null
}

const mapStateToProps = createStructuredSelector({
  isAuthenticated: selectIsUserAuthenticated,
  isFetching: selectIsFetching
});

export default connect(mapStateToProps)(ProtectedRoute);


//User reducer

const INITIAL_STATE = {
  isAuthenticated: false,
  currentUser: null
};

const UserReducer = (state = INITIAL_STATE, action) => {
  const { type, payload } = action;
  switch (type) {
case UserActionTypes.FETCH_USER_SUCCESS: {
  return {
    ...state,
    isAuthenticated: true,
    currentUser: payload
  };
}
case UserActionTypes.FETCH_USER_ERROR: {
  return {
    ...state,
    isAuthenticated: false,
    currentUser: null
  };
}
default:
  return state;
  }
};

export default UserReducer;

1 Ответ

0 голосов
/ 28 марта 2020

Какой тип аутентификации вы используете?

Если вы используете JWT и храните токен в localStorage, вы можете сделать что-то вроде этого:

const isAuthorized = isLoggedIn || localStorage.get('token');
/* isLoggedIn - user has just logged in with Login Page,
localStorage.get('token') - user refreshed page and he has a token,
you don't want to redirect him until token fails */

Итак, вы думаете о пользователе с токен авторизован, но он не может видеть никаких данных бэкэнда, потому что ему нужно их получить.

Если его токен недействителен, бэкэнд вернет 401 ответ, и вы очистите токен пользователя и перенаправите его для входа в систему. .

Вы также можете использовать два блока Switch.

const renderPrivateRoute = (item, index) => (
  <PrivateRoute key={index} {...item} />
);
const renderPublicRoute = (item, index) => (
  <PublicRoute key={index} {...item} />
);
/* ... */
{
  isAuthorized ?
(<Switch>
    {privateRoutes.map(renderPrivateRoute)} 
    <Route
        path="*"
       render={() => <Redirect to={{ pathname: DEFAULT_PRIVATE_ROUTE }} />}
    />
</Switch>) :
(<Switch>
    {publicRoutes.map(renderPublicRoute)}
    <Route
       path="*"
        render={() => <Redirect to={{ pathname: DEFAULT_PUBLIC_ROUTE }} />}
    />
</Switch>)
}

Второй способ использовать React Suspense, но он все еще экспериментальный. Вы также можете попробовать сделать что-то подобное самостоятельно. https://reactjs.org/docs/concurrent-mode-suspense.html

Третий способ - сохранить ваше хранилище. Посмотрите на пакет redux-persist npm.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...