Як налаштувати автентифікацію користувача за допомогою React, Redux та Redux Saga

ОНОВЛЕННЯ (12.02.2019): Нещодавно я оновив цей проект найновішими реакційними маршрутизаторами, тобто версією 4.3.1, яка є response-router-dom. Будь ласка, перейдіть до його сховища, щоб переглянути зміни.

У своєму попередньому блозі я писав, як написати масштабовану архітектуру в Node.js. Оскільки я використовував листоношу для тестування роботи цієї платформи, я вважав, що було б непогано реалізувати її на стороні клієнта. Щоб написати його сторону клієнта, я вирішив використати стек технологій нижче:

  • Зреагуйте
  • Redux
  • Редукс-Сага
  • Маршрутизатор React

Цей пост передбачає, що ви вже знаєте реакцію та основні концепції Redux та Redux-Saga.

Починаємо

Клонувати моє попереднє сховище блогів. CDу свою кореневу папку та запустіть npm install. Це встановить усі залежності.

По-друге, встановіть mongodbу вашій машині. Після встановлення запустіть сервер mongo за допомогоюmongodу вашому терміналі, якщо це не запущено як послуга на вашому комп'ютері.

Потім переконайтеся, що пакет nodemon встановлений на вашому комп'ютері в усьому світі . Перейдіть до папки на стороні сервера та запустітьnodemon index.jsдля запуску серверного сервера.

Тепер, коли наш сервер запущений і працює, настав час зайнятися його реалізацією на стороні клієнта.

Якщо ви ще не встановили create-react-appпотім продовжуйте встановлювати його, використовуючи наступну команду.

npm install create-react-app -g

Ця команда встановить create-react-appглобально .

Створіть проект

Тепер настав час створити проект. Використання:

create-react-app react-login

Це створить новий проект з назвою react-login. Просуньтеся cdдо цієї папки. Відкрий свійpackage.jsonфайл у вашому улюбленому редакторі та додайте такі залежності:

Нам не потрібні додаткові властивості у цьому package.jsonфайлі. Ми можемо просто їх видалити, але я залишу це як є і рухаюся вперед, щоб дістатись до цікавої частини цього блогу.

Тепер просто запустіть:

npm install

який встановить усі залежності, про які ми згадали вище.

Індексний файл

Для початку відкрийте index.jsфайл і помістіть код нижче в цей файл.

У цьому коді ми імпортуємо reactта react-dom. Потім ми імпортуємо Routerі browserHistoryз react-router. Вони потрібні для цілей маршрутизації, які я буду використовувати далі вroutes/index.jsфайл. Далі ми імпортуємо Provider, це використовується для забезпечення зберігання дочірніх компонентів.

configureStoreі routesце те, що ми збираємося імпортувати наступним, і що я впроваджую через секунду. Просто імпортуйте їх як є та використовуйте у цьому файлі, як показано вище.

Тепер наш індексний файл налаштовано.

Конфігурація магазину

Створіть нову папку з назвою storeвсередині srcпапку. Усередині цієї нової папки, створіть файл з ім'ям configureStore.js,і вставте наступний код у цей файл.

Спочатку ми імпортуємо createStore, що буде звично createStore, і applyMiddleware, яке буде використано, застосовувати проміжні засоби до нашого магазину - саги в цьому випадку, але про це ми поговоримо пізніше в цьому блозі - з redux.

Потім ми імпортуємо rootReducer- ми збираємося створити це пізніше. Наразі просто імпортуйте його та використовуйте як є. Далі слід функція configureStore, яка повертає об’єкт, викликаючи createStoreфункцію та передаючи її rootReducerяк параметр.

Нарешті, export configureStoreробить configureStoreдоступним index.jsфайл, побудований раніше.

Тепер це нам не в шлях, продовжуйте і створюйте src/reducersпапку, створіть файл index.js і вставте в цей файл код нижче.

Цей файл відповідає за імпорт решти редукторів всередині папки редукторів, їх комбінування та експорт, щоб вони були доступними для використання configureStore.js. Ми внесемо зміни до цього файлу, коли додамо нові редуктори пізніше в цьому блозі.

Файл маршрутизації

Час для файлу маршрутів. Вперед і створітьsrc/routesі всередині цієї папки створіть index.jsфайл. Тепер відкрийте його та вставте код нижче.

Основною метою цього файлу є обробка маршрутизації в нашому проекті. Імпорт файлів React, Routeі IndexRoute. Після цього нам потрібен контейнер, у цьому випадку я імпортую container/App, який ми збираємося написати найближчим часом. Далі йде RegisterPage, що є компонентом, і ми також це напишемо.

У батьківському Route, коли домашній шлях збігається, ми просто відтворюємо наш Appконтейнер. На IndexRouteкористувачів бачитимуть RegisterPageвиводяться всередині Appконтейнера.

Контейнер

Тепер настав час для контейнера. Вперед і створіть нову папку з назвою container. Усередині цієї папки створіть новий файл із назвою App.jsта помістіть у нього вказаний нижче код.

Це досить просто. Основною метою цього файлу є рендерінг решти компонентів.{this.props.children}служить цій меті.

Реєстрація

Тепер настав час для registerPage. Створіть нову папкуsrc/componentsі створити компонент усередині папки компонентів, який називаєтьсяregisterPage.js. Вставте наведений нижче код у цей компонент.

На даний момент це дуже простий компонент. Ми відредагуємо це пізніше, щоб додати реєстраційну форму та додати до неї деякі функції.

Вихідні дані

Створивши всі папки та файли вище, запустіть npm startпроект і відкрийте//localhost:3000у вашому браузері. Ви повинні бачити нижченаведений результат.

Натискання на логін тут не призведе до перенаправлення на маршрут входу, який ми виправимо далі.

Змушуючи це працювати

Маршрутизація

Щоб маршрутизація працювала, спочатку створіть новий компонент всередині папки компонентів. Назвіть його loginPage.jsта розмістіть наведений нижче код всередині цього компонента.

Цей компонент дуже простий. Він надає основний вміст та посилання для реєстрації компонента.

Тепер відкрийте routes.jsфайл, який ми вже створили вище, і внесіть наступні зміни.

Змініть індексний шлях на, LoginPageоскільки ми хочемо, щоб користувачі потрапляли на компонент входу, коли вони відвідують домашню сторінку. Перш ніж це зробити, імпортуйте його з папки компонентів.

Тепер оновіть свій браузер, і ви зможете побачити loginPageспочатку. Коли ви натискаєте на посилання “Зареєструватися тут”, воно registerPageмає бути відображено.

Зараз у нас працюють основні маршрути.

Вхід та реєстрація

Реєстрація

Для того, щоб процес входу працював, я спочатку оброблю процес реєстрації, щоб ми додали декількох користувачів до нашої бази даних. Отже, давайте відкриємо components/registerPage.jsта оновимо його з наведеним нижче вмістом.

Здається, зараз у цьому файлі багато коду, але все просто. Спочатку ми імпортуємоconnectщоб з'єднати наш storeзregisterPageкомпонент. Потім ми імпортуємоregisterUserActionякий ми напишемо далі.

Усередині renderфункції спочатку я перевіряю відповідь сервера, якщо вона існує, потім присвоюю успіх та властивості повідомлень, які отримуються від сервера. Це може бути окрема функція, але для простоти я помістив їх у renderфункцію.

Далі є реєстраційна форма. Коли користувач натискає кнопку реєстрації, він запускає onHandleRegistrationфункцію, яка отримує введені користувачем дані із форми, таdispatch registerUserActionз їхніми даними як параметрами. Ми збираємося писати дії на наступному кроці.

Для того, щоб вищезгаданий код працював, нам потрібно mapStateToProps, як це робиться внизу компонента, а потім підключити його до registerPageкомпонента в кінці.

Дії

Тепер настав час додати дії. Вперед і створітьsrc/actionsпапку. Створітьindex.jsфайл і помістіть в нього код нижче.

Цей код експортує деякі константи, які ми будемо використовувати протягом нашого проекту.

Тепер продовжуйте і створюйте authenticationActions.jsфайл у тій самій папці та помістіть у нього код нижче.

Тут я імпортую файл індексу, який експортує константи, а потім export registrationUserActionповертаю об'єкт із типом дії та даними користувача. Тип дії в цьому випадку є REGISTER_USER. Ця дія буде надіслана, коли користувач намагатиметься зареєструватися, і ця дія буде доступна протягом нашого проекту, який ми будемо слухати в наших сагах.

Саги

Зараз ми знаходимося на етапі, коли ми можемо представити наші саги у своєму проекті. Якщо ви новачок у Redux-Saga, то я пропоную вам пройти цей блог, перш ніж продовжити.

Якщо ви вже знаєте про саги, створіть src/sagasпапку. Створітьindex.jsфайл і помістіть у цей файл код нижче.

У наведеному вище файлі спочатку я імпортую forkз effectsтаwatchUserAuthenticationвід watchers- який ще не існує, але ми зробимо цей файл наступним. Потім я просто експортую функцію генератора і розгалужую watchUserAuthentication.

Тепер створіть watcher.jsфайл у тій же папці, що і вище, і помістіть у цей файл код нижче.

Знову ж таки, я імпортую takeLatestефект від redux-saga, потім registerSagaвід authenticationSaga.js, який ми створимо далі. Далі імпортуйте actions/index.jsяк типи.

Я експортую функцію генератора, яка в основному стежить за REGISTER_USERдією і робить виклик registerSaga.

Тепер давайте створимо authenticatioSaga.jsсагу в тій же папці, що і вище, і помістимо в цей файл код нижче.

У цій сазі я імпортую ще пару ефектів - putі callвід redux-saga. Потім registerUserServiceімпортується з service/authenticationService.js. Я імпортую всі дії як типи з actions/index.js. Тоді я експортую функцію генератора registerSaga.

Ця функція відповідає за виклик registerUserService, який робить виклик ajax на наш сервер для реєстрації нового користувача - що я напишу після цього кроку. Він отримує відповідь від registerUserServiceі проводить REGISTER_USER_SUCCESSдію. Якщо сталася помилка, вона запускає REGISTER_USER_ERRORдію.

Імпортуйте саги

Тепер, коли у нас є свої саги, настав час імпортувати їх у наш магазин. Відкрийте store/configureStore.jsта оновіть його вміст із вмістом нижче.

Тут я вводжу createSagaMiddleware, rootReducerі rootSaga. Потім, всередині configureStoreфункції, я створюю нову sagaMiddlewareі передаю її у createStoreкористування applyMiddlewareфункцією. Нарешті, я запускаю rootSaga.

Тепер настав час створити src/servicesпапку та створити нову першу службу. Назвіть цеauthenticationService.jsта розмістіть наведений нижче код у цій службі.

Цей файл виконує базовий запит ajax, використовуючи API вибору з деякими параметрами та заголовком. Це досить зрозуміла послуга.

Редуктор

Тепер, коли ми робимо запит до сервера, настав час отримати таку відповідь у нашому компоненті. Для цього нам потрібен редуктор . Вперед і створіть areducers/registerReducer.jsфайл і помістіть в нього код нижче.

Це проста функція редуктора, яка отримує стан і повертає новий стан. Він перевіряє наявність REGISTER_USER_SUCCESSта REGISTER_USER_ERRORдії та повертає новий стан компоненту.

Тепер вперед і відкрийте src/reducers/index.jsфайл та оновіть його таким вмістом.

У цьому rootReducerя буду імпортувати всі редуктори, а потім комбінувати їх перед експортом. Саме з цим я і роблю register.

Запуск оновленого коду

Зараз ми закінчили процес реєстрації. Пора оновити браузер, перейти до маршруту реєстрації та ввести деякі дані. Якщо ви вводите існуючу електронну адресу, ви побачите нижченаведений результат.

Якщо ви вводите новий електронний лист, то вас слід перенаправити на loginPage, що ми збираємось реалізувати наступним чином.

Увійти

Нам пора ввійти в систему користувача після реєстрації. Вперед і відкрийcomponents/loginPage.jsфайл та оновіть його таким вмістом.

Цей компонент майже такий самий, як registerPage. Різниця лише в тому, що він відправляєloginUserActionякий ми будемо писати далі. Інша відмінність полягає в тому, що, якщо відповідь сервера буде успішною, я отримаю файл JWT token. Я зберігаю цей жетон у localStorage. Ви можете використовувати інший метод, але в цьому прикладі я використовую цей підхід.

Вперед і відкрий actions/authenticationActions.jsта оновіть його таким вмістом.

Тут я експортую нову loginUserActionфункцію з LOGIN_USERтипом дії та user payload.

Перш ніж рухатися вперед, відкрийте actions/index.jsфайл та оновіть його вміст наступним чином.

Тепер вперед і відкрийте sagas/watchers.jsфайл та оновіть його вміст наступним чином.

Тут я просто імпортую loginSagaі викликаю його, коли він отримує файлLOGIN_USERдії.

У нас loginSagaпоки що немає. З цієї причини відкрийтеsagas/authenticationSaga.jssaga та оновіть її зміст наступним чином.

Тут я імпортую додаткову послугу - loginUserService, яку я буду реалізовувати наступним чином, а потім експортую нову функцію генератора з назвою loginSaga, яка робить майже те саме, що і registerSaga.

Тепер відкрийте services/authenticationService.jsслужби та оновіть її вміст наступним чином.

Тут я додаю loginUserService, який робить майже те саме, що і registerUserService, тобто надсилає запит ajax для входу користувача.

Тепер, коли ми успішно надіслали запит на сервер, настав час отримати відповідь від нашого сервера на наш компонент для входу. Для цього створіть новий редуктор reducer / loginReducer.js і помістіть в нього код нижче.

Це робить майже те ж саме, що registerReducer- прослуховування LOGIN_USER_SUCCESSта LOGIN_USER_ERRORдії та повернення нового стану.

Тепер відкрийте reducers/index.jsфайл та оновіть його вміст за допомогою коду нижче.

Ось я імпортую loginReducerта комбіную його з, registerперш ніж повернути як rootReducer.

Після цього оновіть браузер і введіть електронну адресу, яка ще не зареєстрована. Після натискання кнопки входу ви повинні побачити нижченаведений результат.

Якщо ви введете зареєстрований електронний лист, тоді запит повинен бути успішним, але ви не повинні бачити нічого, оскільки я не реалізував dashboardPageкомпонент. Це буде доступно лише після успішної автентифікації. Сказавши це, давайте це реалізуємо.

Сторінка інформаційної панелі

Тепер створіть components/dashboardPage.jsі помістіть наведений нижче код у цей компонент.

Це дуже простий компонент - він лише повертає Dashboardтекст.

Тепер відкрийте routes/index.jsмаршрут та оновіть його вміст наступним чином.

Ось я роблю кілька нових речей. Спочатку я імпортую a dashboardPageта додаю його до route. Колиdashboardмаршрут доступний, requireAuthфункція буде активована. Ця функція перевіряє, є користувач loggedInчи ні. Щоб перевірити це, я шукаюtokenin localStorage, який я зберігав у loginPageкомпоненті при успішному вході в систему. Якщо воно існує, dashboardPageвоно відображається користувачеві.

Тепер, коли ви оновлюєте сторінку у своєму браузері, вводите зареєстрований електронний лист і натискаєте клавішу Enter, ви побачите наведені нижче результати.

Отже, це повноцінна система входу, що використовує React, Redux та Redux-Saga. Якщо ви хочете переглянути весь проект, клонуйте це сховище.

Сподіваюся, вам сподобався цей пост.