reactjs – Cookie-based authentication via REST API in react-admin – Stack Overflow

Adding blueprintjs for styling

BlueprintJS будет использоваться нами для стилизации приложения. Итак, давайте настроим его:

Давайте включим файлы CSS для BlueprintJS в файл index.css:

Также обратите внимание на стили, которые мы добавили для выравнивания содержимого страницы по центру.

Application architecture

Процесс входа в систему будет выглядеть следующим образом:

Аутентифицированный запрос будет выглядеть следующим образом:

Creating authentication related functions

Теперь давайте разработаем несколько функций для аутентификации. Следующий код должен использоваться для создания файла authenticate.js в корневом каталоге:

authenticate.js

Требуется («паспорт»);1 -й паспорт

%MINIFYHTML498595270a4c70dff48e21444064ffe913%

2const jwt =require("jsonwebtoken")

3const dev = process.env.NODE_ENV!=="production"

4

5exports.COOKIE_OPTIONS={

6 httpOnly:true,

7

8

9 secure:!dev,

Подписано: True 10

11 maxAge:eval(process.env.REFRESH_TOKEN_EXPIRY)*1000,

SameSite: «Нет» 12

13}

14

15exports.getToken=user=>{

16return jwt.sign(user, process.env.JWT_SECRET,{

17 expiresIn:eval(process.env.SESSION_EXPIRY),

18})

19}

20

21exports.getRefreshToken=user=>{

22const refreshToken = jwt.sign(user, process.env.REFRESH_TOKEN_SECRET,{

23 expiresIn:eval(process.env.REFRESH_TOKEN_EXPIRY),

24})

Обновления 25 -й

26}

27

28exports.verifyUser= passport.authenticate("jwt",{ session:false})

Creating jwt strategy

Создайте файл JwtStrategy.js в папке strategies с тем же кодом, что и локальная стратегия:

As you could see we are using fromAuthHeaderAsBearerToken function, specifying JwtStrategy
to extract the JWT from the authentication bearer header.

Creating local strategy

Теперь давайте разработаем локальную стратегию, которая будет применяться при регистрации и входе в систему:

Creating login and registration components

Давайте теперь создадим компоненты для входа в систему и регистрации с помощью BlueprintJS:

How can i get around this?

Где допустимо размещать состояние клиента, если локальное хранилище может быть злоупотреблено внешними скриптами (например, теми, которые находятся в расширениях браузера), и если аутентификация может быть выдана за cookies?

Согласно документации Auth0, аутентификация одностраничного приложения с помощью cookies возможна только в том случае, если ваше приложение:

  • Обслуживает клиента, используя свой собственный бэкенд
  • Имеет тот же домен, что и ваш бэкенд
  • Делает вызовы API, требующие аутентификации с вашим бэкендом
  • Таким образом, существует способ безопасного использования cookies для аутентификации.

Installing passport related packages

Давайте установим упомянутые выше пакеты:

Localstorage

Для хранения временных переменных используйте localStorage.

Похоже на Local Storage, это так.

  • Изменения доступны только в окне (или в таких браузерах, как Chrome и Firefox). Внесенные изменения сохраняются и доступны как для текущей страницы, так и для последующих посещений сайта в том же окне. После закрытия окна хранилище удаляется
  • Данные доступны только в том окне/вкладке, в котором они были установлены.
  • Данные не являются постоянными, т.е. они будут потеряны при закрытии окна/вкладки. Как и localStorage, он работает с той же исходной политикой. Поэтому сохраненные данные будут доступны только из того же источника.

Other advantages of using jwt:

С помощью команды ниже можно создать новый проект Node.js:

В удобном для вас редакторе кода откройте директорию, в которой вы выполнили вышеупомянутую команду, а затем обновите файл package.json с помощью сценария запуска:

Чтобы установить пакеты, введите приведенную ниже команду:

Now let’s create a file named .env in the root directory of the project.
This file will have all the configurations and secrets used by the server. You will come across these variables throughout this post.

.env files with production secrets should not be pushed to the code base.
In a deployed environment, set environment variables in the server configuration.

Создайте файл connectdb.js в директории utils и поместите его туда:

As the name indicates, it helps in connecting to the MongoDB instance specified in .env file.
You may use either a local instance or
connect to a cloud provider like MongoDB Atlas.

Далее напишите следующий код в файле с названием index.js:

index.js

1const express =require("express")

Требуется ("cors") 2const

3const bodyParser =require("body-parser")

4const cookieParser =require("cookie-parser")

5

6if(process.env.NODE_ENV!=="production"){

7

8required("dotenv").config ().

9}

10require("./utils/connectdb")

11

12const app =express()

13

14app.use(bodyParser.json())

15app.use(cookieParser(process.env.COOKIE_SECRET))

16

17

18

Process.env.whiteListed_Domains как постоянный

20? process.env.WHITELISTED_DOMAINS.split(",")

21:[]

22

23 Константные корсопции =

Происхождение: функция (обратный вызов, происхождение)

25if(!origin || whitelist.indexOf(origin)!==-1){

26callback (null, песок)

27}else{

28callback(newError("Not allowed by CORS"))

29}

30},

31

Правда, 32 полномочия

33}

34

35App.Brug (cors (корсопции))

36

37app.get("/",function(req, res){

38 res.send («успех»);

39})

40

41

42

43const server = app.listen(process.env.PORT||8081,function(){

44const port = server.address().port

45

« Приложение началось в порту:», 46console.log

47})

Здесь сервер запускается на порту 8081, и маршрут / передается по проводу с успешным ответом.

Используйте следующую команду для запуска сервера (также можно использовать npm start или nodemon)

Теперь в консоли вы должны увидеть следующий вывод:

Session management:

Для отслеживания логинов, корзин, игровых результатов и других действий требуется сервер.

Session storage

Преобразуйте хранилище in-memory в sessionStorage, чтобы оценить преимущества хранения вне памяти. Запустите App.js

  1. nano src/components/App/App.js

Удалите вызов useState, затем добавьте функции setToken и getToken. Далее вызовите getToken, а затем присвойте результаты переменной token:

auth-tutorial/src/components/App/App.js

Showing welcome screen

Мы можем выбрать, отображать ли форму входа/регистрации или экран приветствия, теперь, когда маркер сохранен в контексте.

Начнем с изготовления приветственного элемента:

Source code and demo

You can view the complete source code of the client here,
the server here, and a demo here.

Submitting the login and registration forms:

Теперь прикрепим обработчик отправки к форме входа в систему:

Login.js

1import{ Button, Callout, FormGroup, InputGroup }from"@blueprintjs/core"

2import React,{ useContext, useState }from"react"

3import{ UserContext }from"./context/UserContext"

4

5constLogin=()=>{

6const[isSubmitting, setIsSubmitting]=useState(false)

7const[error, setError]=useState("")

8const[email, setEmail]=useState("")

9const[password, setPassword]=useState("")

10const[userContext, setUserContext]=useContext(UserContext)

11

12constformSubmitHandler=e=>{

Предотвратить () в строке 13.

14setIsSubmitting(true)

15setError("")

16

Что-то пошло не так! 17const genericErrorMessage Пожалуйста, попробуйте еще раз позже.

18

19fetch(process.env.REACT_APP_API_ENDPOINT"users/login",{

Метод: «Пост»

21 квалификация: «включить»,

« Контент-тип»: «Приложение/JSON», 22 заголовки

Имя пользователя: электронная почта, пароль;Тело: json.stringify;

24})

25.then(asyncresponse=>{

26setIsSubmitting(false)

27if(!response.ok){

28if(response.status ===400){

Пожалуйста, заполните все поля точно! 29setError

30}elseif(response.status ===401){

" Недопустимая комбинация электронной почты и пароля", установите ошибку 31.

32}else{

33setError(genericErrorMessage)

34}

35}else{

36const data =await response.json()

37setUserContext(oldValues=>{

38return{...oldValues, token: data.token }

39})

40}

41})

42.catch(error=>{

43setIsSubmitting(false)

44setError(genericErrorMessage)

45})

46}

47return(

48<>

49 ошибок и ошибок

50

51

52

53id="email"

54placeholder="Email"

55type="email"

56value={email}

57onChange={e=>setEmail(e.target.value)}

58/>

59

60

61

62ID = "Пароль"

63placeholder="Password"

64type = "пароль"

65value={password}

66onChange={e=>setPassword(e.target.value)}

67/>

68

69

70intent = "Первичный"

71disabled={isSubmitting}

72text={`${isSubmitting ?"Signing In":"Sign In"}`}

73fill

74type = "отправить"

75/>

76

77

78)

79}

80

Войдите с 81ExportDefault.

В приведенном выше коде,

The problem

Вы можете подумать, что использование cookie так же просто, как использование их в браузере, но, к сожалению, это не так, поскольку React Native зависит от нативных (Android и iOS) API, написанных на Java и Objective-C.

Нативные сетевые API по умолчанию сохраняют файлы cookie, что поначалу может показаться нормальным. Однако через некоторое время и после нескольких запросов запросы могут стать непоследовательными, что может привести к тому, что сервер откажет в доступе, потому что отправленные нами cookies оказались недействительными, хотя на момент передачи запроса они были действительны.

The solution

Первой мыслью, которая пришла мне в голову, было взять под контроль управление файлами cookie, просто сохраняя их на устройстве (например, Async Storage).

В настоящее время поток выглядит следующим образом:

  1. После успешного соединения сервер отвечает статусом и cookies
  2. Cookies хранятся на устройстве (асинхронное хранение)
  3. Заголовок каждого последующего запроса заполняется cookies из хранилища устройства

И я верил, что это лучший вариант. Легко, да? Но давайте посмотрим на то, как обстоят дела сейчас.

Через некоторое время все стало работать гладко, но те же проблемы вернулись, и я вернулся к тому, с чего начал. Как упоминалось ранее, React Native имеет собственное управление cookie, которое я теперь дополнил. Естественно, родной API вмешивался в мою реализацию и каждый раз брал верх, заменяя отправленный мной cookie на свой собственный и приводя к тем же проблемам.

П РИМЕЧАНИЕ: Я пока не совсем уверен, что именно это происходит на родной стороне.

После некоторого исследования я обнаружил react-native-cookies. Это библиотека React Native для управления куки-файлами, которая позволяет управлять нативными куки-файлами. Поскольку нативное управление куки теперь можно изменять, стратегия хранения куки на устройстве может быть усовершенствована.

Как уже было сказано, управление нативными файлами cookie повлияло на сохраненные файлы cookie. Поэтому давайте полностью удалим родные файлы cookie и будем использовать только те, которые в данный момент находятся на устройстве. Очистка встроенных сохраненных файлов cookie будет самым простым действием.

В этом может помочь упомянутая выше библиотека.

import CookieManager from 'react-native-cookies'
import AsyncStorage from '@react-native-community/async-storage';

const client = async () => {
	await CookieManager.clearAll() //clearing cookies stored 
                                       //natively before each 
                                       //request
	const cookie = await AsyncStorage.getItem('cookie')
	return await fetch('api/data', {
		headers: {
			'cookie': cookie
		}
	})
}

Вместе с запросами передаются только те файлы cookie, которые были сохранены на устройстве вручную, поскольку встроенные файлы cookie очищаются перед каждым запросом. Главное преимущество постоянного использования приложения при использовании этого простого исправления заключается в том, что больше нет никаких мешающих друг другу файлов cookie.

Under development and construction

Источники и ссылки:

Useful for you, consider buying me a coffee. thanks!

ETH:0xdfaf8F1bCaaB513A14E5a0B8C2D0bF7EE6ECabbc

Vulnerability method

Подделка межсайтовых запросов (CSRF) Куки: Межсайтовый скриптинг (XSS) Локальное хранилище

Why jwt is stored in the memory? why not localstorage?

You might have observed in many blogs and videos informing not to store JWT or any authentication details in local storage or client-side cookies.
The reason they might have provided is local storage and client-side cookies are prone to XSS attack.

However, storing JWT in the memory does not prevent reading it if there is an XSS vulnerability, it just makes it a bit difficult for the attacker to read it.
So the goal must be to develop the application without XSS vulnerability (or any other for that matter) and not to worry about where to store the JWT!

Существует отличная статья, объясняющая, почему избегать LocalStorage для токенов – неправильный ход.

Wrap up

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

Учитывая, что природа самой проблемы не до конца понятна, я считаю важным отметить, что это не единственное решение, которое можно использовать. Решения, описанные в этой статье, также работают без каких-либо библиотек.

Implementing the front end

https://www.youtube.com/watch?v=wrvcqovzKxs

Используйте следующую команду для начала нового проекта react.

Похожее:  Авторизация и деавторизация компьютера для работы с покупками, совершенными в iTunes Store - Служба поддержки Apple (RU)

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *