ОБНОВИТЬ

Форматирование на среднем уровне - это головная боль, особенно если вы пытаетесь скопировать и вставить черновик, написанный в уценке. Я сдаюсь. Вот ссылка на сообщение в моем уродливом (но правильно отформатированном) блоге: http://lonesword.in/programming/web/2017/06/02/react-router-login.html

Эта статья вдохновлена ​​прекрасным руководством Скотта Луптовски о том, как добавить аутентификацию в свое приложение React. Я пытаюсь заново изобрести колесо, потому что в исходной статье цитируется более старая версия react-router, а инструкции не работают, если вы используете react-router 4.x. При переходе с 3.x на 4.x происходит множество критических изменений, и на все почему есть ответ здесь

Отказ от ответственности

Я не реактивный ниндзя, рок-звезда, паладин или что-то в этом роде. Просто чувак с добрыми намерениями, которому пришлось провести весь вечер, пытаясь понять, как работает аутентификация с помощью response-router 4.x, когда в Интернете были только учебники, использующие 3.x. Так что прислушайтесь к моему совету с долей скепсиса - возможно, я не следую лучшим практикам.

Цель

Ваше замечательное новое приложение требует, чтобы пользователь вошел в систему, прежде чем ему будет разрешено выполнять определенные действия. Например, если вы создавали следующий твиттер, ваши пользователи не должны иметь возможность твитнуть, если они не вошли в систему. Идея здесь состоит в том, чтобы поместить определенные шаблоны URL / страницы за стеной аутентификации, чтобы, если пользователь посетит эту страницу и пользователь не авторизован, он должен быть перенаправлен на страницу авторизации. Если пользователь уже вошел в систему, продолжайте показывать запрошенный контент - и пользователь не будет иметь никакого представления о каратэ, которые мы делали за сценой. Если пользователь попытается перейти на страницу, которой не существует, мы также должны показать компонент 404.

Как сделать

Решение достаточно простое. Так же, как Скотт объяснил в исходной статье, мы создаем компонент React, содержащий логику входа в систему. Этот компонент охватывает все маршруты, для которых требуются аутентифицированные пользователи. Наша точка входа в приложение будет выглядеть примерно так:

ReactDOM.render(
 <Router>
 <App />
 </Router>,
 document.getElementById(‘app’)
);

Но куда делись все маршруты? В response-router 4.x вы не можете определять все маршруты в одном месте. Да, ты читаешь это правильно. Итак, наш App component будет выполнять свою роль в маршрутизации:

class App extends Component {
 constructor(props){
  super(props);
 }
render() {
  return (
   <div>
    All the awesomeness in the world converged to a single component.
    <Switch>
     <Route exact path="/" component={Home} />
     <Route path="/" component={RootRouteWrapper} />
    </Switch>
   </div>
  
  )
 }
}

Так что мы здесь делаем? Если URL-адрес в точности совпадает с /, мы отображаем Home component. Для всего остального, что является подмножеством /, мы визуализируем RouteRouteWrap, который впоследствии будет маршрутизировать наши запросы. Таким образом, все остальные шаблоны URL (например: «/ pizza», «/ pizza / yummy») перейдут на рендеринг компонента «RootRouteWrapper». Но что там делает этот компонент Switch? Если бы мы не заключили маршруты в `Switch`, response-router отобразил бы все маршруты, соответствующие URL-адресу. Поэтому, если пользователь посещает your-awesome-app.com, сработают все маршруты для `/` - как `Home`, так и` RootRouteWrapper`! Если ваши маршруты заключены в `Switch`, response-router отобразит ** только ** первое совпадение - в нашем примере компонент` Home`.

OK. Итак, теперь мы можем показать домашнюю страницу. Что снова делает компонент `RootRouteWrapper`?

class RootRouteWrapper extends Component {
 render() {
  return (
   <div id="RootRouteWrapper">
    <Switch>
     <Route exact path="/login" component={LoginRedirectComponent} />
     <Route path = "/tweet" component={EnsureLoggedInContainer} />
     <Route component={PageNotFound} />
    </Switch>
   </div>
  )
 }
}

Здесь мы определяем 2 маршрута - / login, чтобы показать пользователю приглашение для входа в систему, и / tweet, чтобы пользователь мог опубликовать твит. Теперь / tweet должен быть доступен, только если пользователь вошел в систему. EnsureLoggedInContainer - это волшебный компонент, который будет обрабатывать логику входа в систему за нас. Идея состоит в том, чтобы настроить все маршруты, требующие аутентификации, для отображения EnsureLoggedInContainer. Вы также можете видеть, что мы определили маршрут, который будет отображать компонент `PageNotFound`, если URL-адрес не соответствует ни одному из настроенных маршрутов. Переходим к нашей логике входа в систему:

import {Route, Switch, withRouter} from 'react-router-dom';
class EnsureLoggedInContainer extends Component {
 constructor(props){
  super(props);
 }
componentDidMount(){
  const {dispatch, currentURL, isLoggedIn} = this.props;
if(!isLoggedIn){
   this.props.history.replace('/login');
  }
 }
render() {
  const {isLoggedIn} = this.props;
return (
   <Switch>
    <Route path="/tweet" component={Tweet} />
   </Switch>
  )
}
}
export default withRouter(EnsureLoggedInContainer);

Предполагается, что компонент `Tweet` показывает пользователю поле ввода для ввода сообщения.
Обратите внимание, как мы снова объявили маршрут для` / tweet` внутри `EnsureLoggedInContainer`. Когда пользователь переходит в / tweet, RootRouteWrapper отображает EnsureLoggedInContainer, который, в свою очередь, отображает Tweet. Если пользователь не вошел в систему, componentDidMount перенаправит пользователя на страницу входа. Помните, что вам нужно экспортировать класс с помощью `withRouter`, чтобы история была доступна в свойствах. Кроме того, вам нужно будет поддерживать состояние приложения отдельно - в этой статье предполагается, что вы установили необходимую инфраструктуру для передачи isLoggedIn в качестве опоры для EnsureLoggedInContainer. isLoggedIn должен исходить из состояния вашего приложения - и здесь наиболее популярным выбором является response-redux. Как использовать react-redux для передачи свойств вашему компоненту - выходит за рамки этой статьи. Если вам интересно, есть действительно хорошее введение [здесь] (http://redux.js.org/docs/introduction/)

Если вы хотите добавить еще одну страницу, отображающую твит, скажем, `/ tweet / 1`, которая будет показывать твит с идентификатором 1 в компоненте` TweetContainer`, вам придется написать необходимую логику маршрутизации внутри `Tweet` составная часть. `/ tweet /: id` автоматически потребует аутентификации, поскольку его родительский маршрут -` / tweet` - отображает `EnsureLoggedInContainer`.

Предостережения

Чтобы добавить новый маршрут, требующий аутентификации, необходимо внести изменения в двух местах - в компоненте RootRouteWrapper, а затем снова в EnsureLoggedInContainer. Интересно, есть ли более элегантное решение