Рубрики
Без рубрики

Управление пользователем с AWS Cognito – (3/3) Последние шаги для полноценного

Cangze Huang Управление пользователями с AWS Cognito – (3/3) Последние шаги на полную прогнозную кнопку AWS Web Boeterplate – Часть 1CMain Содержание Нажмите здесь, нажмите: Начальный Setuppart B: Основная функция PerformancePART C: Последние шаги на Full Fledded Download Github здесь. Последние стесны последние части к этой Грандской Схемы

Автор оригинала: FreeCodeCamp Community Member.

Kangze Huang

Полная веб-ботинка AWS – часть 1С

Скачать github здесь Отказ

Последние шаги

Последние фигуры этой Грандской схеме состоят в том, чтобы завершить штрихи и аутентификацию Backend. То, что мы подразумеваем под дверь, включают:

Backend Authentication означает, что проверка токена JWT, полученная от Cognito или Facebook, чтобы подтвердить органу доступа к защищенным ресурсам. После прикрытия этих функций у нас полностью будет полноценная система управления пользователем на AWS. Вау! Давайте доберемся до этого.

Обновление информации о пользователе

Любая респектабельная система управления пользователем будет иметь возможность изменять атрибуты пользователя, поэтому AWS Cognito не является исключением. Актуальный компонент можно найти в Приложение/SRC/Компоненты/AUTH/PROFILEPAGE.JS Отказ Наш код Cognito внутри Приложение/SRC/API/AWS/AWS-COGNITO.JS , ищите функцию updateUserinfo () Отказ

export function updateUserInfo(editedInfo){ const p = new Promise((res, rej)=>{  const attributeList = []  for(let a = 0; a{              res(userProfileObject)             })          })        });      }    }); }) return p}

Проходим в объекте пользователя, который мы получили от BuildUserObject () , но отредактировано, чтобы включить обновленные значения (в данном случае Agentname ). Внутри нашего обещания мы создаем пустую Атрибутлист Массив, чтобы держать переменные, которые чувствуют себя как подписи () Отказ Это потому, что он делится процессом Theesame! Мы петлю через Editiedinfo объект и для каждого атрибута мы создаем Cognitouserattribute объект для добавления к Атрибутлист множество.

После всего этого сделано, мы создаем КОГНИТЕР Объект из импортированного UserPool обновить сеанс, чтобы мы могли соответственно звонить Updateattributes с Атрибутлист множество. Это будет обновлять наш пользователь Cognito с последними атрибутами, а в обратном вызове мы можем getuserattributes опять таки. С обновленными атрибутами мы называем BuildUserObject Для использования в нашем приложении React-redux. И это все! Почти точный повторение подписи () Отказ

Забыли пароль

Этот тоже мертвый просто. Как всегда, создайте свой КОГНИТЕР с данными из userdata Отказ Теперь мы можем позвонить Забыли слово Отказ

export function forgotPassword(email){ const p = new Promise((res, rej)=>{
   const userData = {     Username: email,     Pool: userPool   }  const cognitoUser = new CognitoUser(userData)
  cognitoUser.forgotPassword({      onSuccess: function (result) {        res({          cognitoUser: cognitoUser,          thirdArg: this        })      },      onFailure: function(err) {         rej(err)      },      inputVerificationCode: function(data) {         res({            cognitoUser: cognitoUser,            thirdArg: this         })      }  })
 }) return p}

ForgoPassword () В основном инициализирует процесс и возвращает КОГНИТЕР Объект, который будет использоваться в React-redux. В объекте обратного вызова мы только используем OnSuccess и OnFailure Отказ ВходВестениеCode не используется здесь, как то, как он используется в Github Docs (см. Case 12) Поскольку мы хотим сделать более красивый интерфейс вместо использования Подсказка () попросить ввода. В OnSucccess Мы возвращаем Cognitouser в наш компонент React React, потому что мы хотим, чтобы страница сброса паролей содержать предварительно заполненную информацию (например, Email ). Когда новый пароль отправлен, conficepasswordsword () просто нужно принять PIN-код , пароль и это Декларация от вызова AWS API. Это то, что он выглядит в приложении React-redux, от Приложение/SRC/Компоненты/auth/resetpassword.js Отказ

verifyPin(){  if(this.props.password == this.props.confirm_password){     this.state.cognitoUserPackage.cognitoUser       .confirmPassword(this.state.pin, this.state.password, this.state.cognitoUserPackage.thirdArg)     setTimeout(()=>{       browserHistory.push("/auth/login")     }, 500)  } }

И это все, что есть для сброса пароля – не слишком сложный, не очень код.

Выйди пользователь

Подписание пользователей действительно просто. Мы называем getCurrentUser () С существованию нашего КОГНИТЕР объект, чтобы мы могли использовать его Подпись () функция. Теперь ваш пользователь выходит в систему!

export function signOutUser(){ const p = new Promise((res, rej)=>{  const cognitoUser = userPool.getCurrentUser()  cognitoUser.signOut() }) return p}

Как мы выполняем это из пользовательского интерфейса? В нашей котельной React-redux маршрутизация приложения обрабатывается Реагистрационный маршрутизатор Хотя состояние приложения обрабатывается Redux. Мы должны объединить два для интеграции аутентификации визуальной пользователей. Наши цели здесь:

Хорошо, так вот мы идем. Во-первых, давайте соблюдаем наше состояние redux, выраженное в Приложение/SRC/Редукторы/AUTHEDUCER.JS Отказ Наша модель состояния выглядит так:

const INITIAL_STATE = {  authenticated: false,  user: null}

Когда мы вошли в систему, мы устанавливаем состояние Redux аутентифицирован правда, и Пользователь до возвращаемой стоимости BuildUserObject () в Приложение/SRC/API/AWS/AWS-COGNITO.JS Отказ Таким образом Itival_state.authenticated Будет использоваться в качестве проверки, универсально во всем приложении, чтобы определить, будет ли пользователь аутентифицирован. В нашем приложении BoaterPlate мы получаем доступ к этой переменной состояния Redux, как Это.props.authenticated Отказ Итак, в нашем компоненте меню в меню на Приложение/SRC/Компоненты/Sidemenu/Sidemenu.js Найти этот клип кода:

{ this.props.authenticated ? : }

После <Боковина />, внутри кудрявого бюстгальтера CKE TS {} у нас есть тройная операция (условный оператор AKA). Это проверит, правит ли первый ARG это .proops.authent Закаленный это правда, и если правда будет ди Splay . Если false, w плохо дисплей . И там у нас это есть! Разные взгляды для аутентифицированных и несовместимых посетителей.

Далее иди в код, выражающий нашу Реагистрационный маршрутизатор Расположен в Приложение/SRC/index.js И найти этот код SNIP:

                                                                                    

Быстрый снижение дерева URL-адреса нашего приложения. На http://ourapp.com/ Мы идем в домашний компонент, представленный как Приложение/SRC/Компоненты/Home.js Отказ На http://ourapp.com/auth/login это компонент входа в систему, представленный как Приложение/SRC/Компоненты/auth/login.js Отказ Но в http://ourapp.com/auth/authentication_page У нас есть этот немного другой маршрут

Этот маршрут имеет Продолжительность () упаковка Аутентификация . компонент. Если мы перейдем к требованию () в App/src/components/auth/requeseauth.js, мы находим другой компонент, но без генерации HTML (то есть нет UI). Это компонент более высокого порядка (HOC), который только добавляет функциональность. В этом случае HOC проверяет, есть ли переменная состояния Redux Это.props.authenticated это правда. Если это не правда, мы просто перенаправляем URL к другому URL-траектору (в этом случае http://ourapp.com/auth/login ). Сделано, это проверка авторитета!

componentWillMount(){   if(!this.props.authenticated){    browserHistory.push('/auth/login')   }}

Теперь вернитесь к Приложение/SRC/index.js Для реализации проверки аутентирования. Мы просто обертываем визуальный компонент внутри нашего не визуального HCO, как функция:

И это вторая цель. Заключительная часть – это наш фонарь общего назначения HCO. Перейти к Приложение/SRC/Компоненты/auth/fightout.js и найти этот SNIP код:

componentWillMount(){    signOutUser()  // signoutLandlord() is a function from `actions` coming from index.js  this.props.logoutUserFromReduxState()  setTimeout(()=>{   browserHistory.push('/auth/login')  }, 500) }

SignateUser () Функция тот, который мы написали в Приложение/SRC/API/AWS/AWS-Cognit.js Отказ Следующий this.props.logoutuserfrreduxState () Устанавливает нашу переменную состояния Redux аутентифицирован к ложе. Наконец мы изменим адрес URL-адрес и вид приложения, используя browserhistory.push ('/auth/login') Через пол секунды (чтобы мы могли отобразить сообщение Goodbye).

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

Получить пользователя из локального хранения

Мы не хотим, чтобы нашим пользователям придется перейти каждый раз, когда они посещают веб-приложение. В идеале мы хотим, чтобы их был сохранен и автоматически зарегистрирован в каждом посещении, пока не выйдут. Поскольку небезопасно сохранить пароль пользователя, мы вместо этого будем хранить токен JWT. На самом деле это управляется для нас AWS Cognito. Перейти к Приложение/SRC/Компоненты/auth/login.js и найдите следующие строки кода:

componentDidMount(){  const savedEmail = localStorage.getItem('User_Email')  if(savedEmail){   this.setState({    email: savedEmail   })  }  retrieveUserFromLocalStorage()   .then((data)=>{    this.props.setUserToReduxState(data)   }) }

ComponentDidMount () Функция будет работать один раз после того, как компонент установлен на веб-странице, которая заключается в том, что когда мы хотим проверить, есть ли пользователь сохраненный вход уже. Мы можем игнорировать первую часть, которая просто проверяет сохраненное электронное письмо и устанавливает его в состояние React CompLent. Важная часть здесь retreteuserFromLocalStorage () , который возвращает userprofileobject что мы можем сэкономить до состояния redux. Напомним, что userprofileobject Используется веб-приложением в виде представления того, кто является пользователем, и все их атрибуты, такие как имя, возраст, высота ..Tc. Простое, так что давайте посмотрим на сочные вещи: функция AWS. Перейти к Приложение/SRC/API/AWS/AWS-COGNITO.JS и найти функцию retreteuserFromLocalStorage () Отказ

export function retrieveUserFromLocalStorage(){ const p = new Promise((res, rej)=>{     const cognitoUser = userPool.getCurrentUser();     if (cognitoUser != null) {         cognitoUser.getSession(function(err, session) {             if (err) {                rej(err)                return             }             localStorage.setItem('user_token', session.getAccessToken().getJwtToken());             const loginsObj = {                 [USERPOOL_ID] : session.getIdToken().getJwtToken()             }         AWS.config.credentials = new AWS.CognitoIdentityCredentials({                 IdentityPoolId : IDENTITY_POOL_ID,                 Logins : loginsObj             })             AWS.config.credentials.refresh(function(){              console.log(AWS.config.credentials)              res(buildUserObject(cognitoUser))             })         });     }else{      rej('Failed to retrieve user from localStorage')     } }) return p}

Так что здесь происходит? Сначала мы создаем КОГНИТЕР Объект, используя UserPool импортируется из aws_profile.js Отказ Однако на этот раз мы используем getCurrentUser () Функция, которая будет вытащить из предыдущей сеансной памяти – полезная функция, которые AWS Cognito обрабатывает для нас! Если мы получим ненулевое значение от getCurrentUser () тогда мы можем предположить, что это действительна КОГНИТЕР Объект и звонок Гемас () Чтобы получить доступ к последним переменным сеанса. Переменная, которую мы заботимся о том, это токен JWT в session.getaccessToken (). getjwttoken () Что мы будем сэкономить на LocalStorage и место в нашу loginsobj (Напомним из части 2, войдите в систему). Это зарегистрирует наш логин в Федеративные личности. Теперь все, что нам нужно сделать, это использовать это, чтобы установить наши учетные данные AWS и обновить их, прежде чем мы позвонить BuildUserObject () и верните его в приложение React-redux. С userprofileobject это возвращено из BuildUserObject () Мы вошли в систему!

Backend аутентификация

Хорошо, так что все это интерфейсные вещи велики, но иметь полный пакет, который нам тоже нужен аутентификация Backend. Допустим, у нас есть ресурс на нашей бэкэнде, который мы только хотим показать, чтобы войти в систему пользователей. Чтобы запросить этот ресурс, мы не будем использовать пароль электронной почты +, потому что это было бы неуверенно отправлять пароль для каждого запроса. Вместо этого мы будем использовать токен JWT, который Cognito поставляется нам. Мы просто расшифруем токен на бэкэнде и проверяем его на ссылки на токен Cognito. Давайте пройдем, как это сделать как общий процесс:

Я включил код для этой бэкенда, написанного в Nodejs, но общий процесс работает с любой бэкэндом. Посмотреть /Bonus_backend/ для кода. Теперь давайте начнем процесс на Frontend ( /App/ ).

Сначала мы отправляем токен JWT с нашего клиентского фронта в заголовке HTTP. Библиотека, которую мы используем для http . Запросы – это Axios , но вы можете использовать любой, что вам нравится, если вы знаете, как включить атрибут заголовка. В AXIOS вы просто поместите объект с заголовком клавишного значения в качестве 3-го аргумента для Пост функция. Найти это в действии в Приложение/SRC/API/myapi.js Отказ

const API_URL = '24.74.347.34' // your backend IP
export function getBackendResource(){  const jwtConfig = {headers: {"jwt": localStorage.getItem("user_token")}}   const p = new Promise((res, rej)=>{    axios.post(API_URL+"/auth_test", null, jwtConfig)     .then((data)=>{      res(data.data)     })     .catch((err)=>{       rej(err)     })   })   return p}

Далее мы должны загрузить набор JWT, который предоставляет нам AWS Cognito. Перейдите на страницу Cognito в консоли AWS и найдите свой регион (например, US-EAST-1 ) и ваш USERPOOLID (например, us-oast-1_fa9dl8swt ). Сейчас используйте их, чтобы заменить следующие позиции и следуйте ссылке.

https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json

Вы должны прибыть на страницу с таким текстом:

{     "keys":[        {           "alg":"RS256",         "e":"AQAB",         "kid":"I7Kw/O0QymLQ8A0pPaXNcv5je7BNYXMCW1HdziUTyrQ=",         "kty":"RSA",         "n":"uIqZqU64ytLpQr3J86NMpjxZBRubRzovkQv22oAeHoxO_w4EZuvEeodCV7WxVatHwcVyH0VrkRsqcoigajJO5Xz3s-Ttz_ozhE8wP-BI3DUPOUNtGiKZirNLf9jluScrCUsyyim2UrF4ub-hsxGSt32GFRMfqrkvz0Ral4K4oeIiBNnX8cu_pbSlDgriBLAh8ago41XhqqSFtWwlP-x_KHJc13RBgETj7HOfEm5tr6ibJlMazL3FOoXehfXQw9Yr0752A2hTKAB8reUJXuAwcyTUa8ZEO6IcnhQiaPmIgltxdm-SHdoPqwR_SQxYzZfQzU9uE78ogWT-xP29Gr08Xw",         "use":"sig"      },      {           "alg":"RS256",         "e":"AQAB",         "kid":"fxyn6hg0ziTNer+mBzqmxqGe38uh4neQPorXo3GAa/s=",         "kty":"RSA",         "n":"hMAECS0ALyFaP7OY4ZN5SXqPpkKOdp_RfNAmeCXhK98rmEnD_9Zzqb5oVviZZoqQ5xEZQBRR7a2JOZxL_JZWX7ObteHMSfNZywk8E9FN4XPMJxStZk5JSceKBd5SPYdLzTR58LFMg4OKONA5aJ1sYUu11zq6yMdUBvEJlwBjBrH4lfSkJ_jg4zSeKxsRcM72oAQ_yCnzO5giPoMjyY8VtqCj7NW_7njyQ-bD1WiGaNCkgBxWwYL_13zCxMJxNopa2vHoca0xn9bct-ysS8zIaB3DjNo_8-GGp_HJ4kNW0TczcILtl4mrl81srGzulvuK-mGF0T31IDY-tZWS3IgQYQ",         "use":"sig"      }   ]}

Сохраните это как свой собственный файл jwt_set.json В вашей спине ( example_backend/app/api/jwt_set.json ) так что его можно ссылаться на ваш процесс аутентификации. Процесс аутентификации (функция) должен выполняться до доступа любого защищенного ресурса. Процесс аутентификации выглядит как этот код, найден в Example_backend/app/api/authcheck.js :

const jwt = require('jsonwebtoken');const jwkToPem = require('jwk-to-pem');const jwt_set = require('./jwt_set.json')
const userPool_Id = "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_6i5p2Fwao"
const pems = {}for(let i = 0; i
exports.authCheck = function(req, res, next){ const jwtToken = req.headers.jwt ValidateToken(pems, jwtToken)   .then((data)=>{    console.log(data)    next()   })   .catch((err)=>{    console.log(err)    res.send(err)   })}
function ValidateToken(pems, jwtToken){ const p = new Promise((res, rej)=>{  const decodedJWT = jwt.decode(jwtToken, {complete: true})  // reject if its not a valid JWT token  if(!decodedJWT){   console.log("Not a valid JWT token")   rej("Not a valid JWT token")  }  // reject if ISS is not matching our userPool Id  if(decodedJWT.payload.iss != userPool_Id){   console.log("invalid issuer")   rej({    message: "invalid issuer",    iss: decodedJWT.payload   })  }  // Reject the jwt if it's not an 'Access Token'  if (decodedJWT.payload.token_use != 'access') {         console.log("Not an access token")         rej("Not an access token")     }     // Get jwtToken `kid` from header  const kid = decodedJWT.header.kid  // check if there is a matching pem, using the `kid` as the identifier  const pem = pems[kid]  // if there is no matching pem for this `kid`, reject the token  if(!pem){   console.log('Invalid access token')   rej('Invalid access token')  }  console.log("Decoding the JWT with PEM!")  // verify the signature of the JWT token to ensure its really coming from your User Pool  jwt.verify(jwtToken, pem, {issuer: userPool_Id}, function(err, payload){   if(err){    console.log("Unauthorized signature for this JWT Token")    rej("Unauthorized signature for this JWT Token")   }else{    // if payload exists, then the token is verified!    res(payload)   }  }) }) return p}

Хорошо, это немного давно, мы даем разбить это одностороннее. Сначала мы импортируем зависимости Nodejs, которые мы хотим и устанавливаем их.

$ npm install jsonwebtoken --save$ npm install jwk-to-pem --save

И тогда мы включаем jwt_set.json а также наш идентификатор пула идентификации. Это 3 зависимости и 1 постоянная.

const jwt = require('jsonwebtoken');const jwkToPem = require('jwk-to-pem');const jwt_set = require('./jwt_set.json')
const userPool_Id = "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_6i5p2Fwao"

Мы создаем еще 1 постоянную под названием PEMS , который создан для Корпус выполнен при загрузке файла.

const pems = {}for(let i = 0; i

На высоком уровне, что происходит, это то, что для каждого ключа в jwt_set.json Мы создаем PEM объект, чтобы быть ценностью того, что ключ jwt_set малыш Отказ Нам не нужно точно знать, что происходит, но в основном мы создаем PEM которые могут быть использованы для совпадения против jwt малыш Исходя из заголовка входящих HTTP-запросов как средство проверки аутентификации. Если вы чувствуете, что вы должны точно знать, что именно эти условия означают, проверьте Анатомия веб-токена JSON Крис Севилью.

В любом случае, двигаться на у нас есть authcheck Функция, которая подтверждает входящий токен JWT от заголовка, используя ValidateToken () Отказ Довольно просто.

exports.authCheck = function(req, res, next){ const jwtToken = req.headers.jwt ValidateToken(pems, jwtToken)   .then((data)=>{    console.log(data)    next()   })   .catch((err)=>{    console.log(err)    res.send(err)   })}

authcheck () Используется в другом месте в вашей бэкэнде, когда функция вызывается перед доступом к защищенному ресурсу. Для Nodejs Экспресс Backend, это будет выглядеть так:

const authCheck = require('./api/authCheck').authCheck
// auth routeapp.get('/auth_test', authCheck, function(req, res, next){ console.log("Passed the auth test!") res.send("Nice job! Your token passed the auth test!")});

Наконец давайте посмотрим на ValidateToken () , который можно разбиться на 6 меньших частей. Пройти в PEMS постоянная и jwt от http . Запросить заголовок. Теперь следуйте 6 этапам процесса проверки, и если все пройти, токен JWT принимается! Обещание будет решено и authcheck () позволит доступу к нашему защищенному ресурсу.

function ValidateToken(pems, jwtToken){ const p = new Promise((res, rej)=>{
  // PART 1: Decode the JWT token  const decodedJWT = jwt.decode(jwtToken, {complete: true})
  // PART 2: Check if its a valid JWT token  if(!decodedJWT){   console.log("Not a valid JWT token")   rej("Not a valid JWT token")  }
  // PART 3: Check if ISS matches our userPool Id  if(decodedJWT.payload.iss != userPool_Id){   console.log("invalid issuer")   rej({    message: "invalid issuer",    iss: decodedJWT.payload   })  }
  // PART 4: Check that the jwt is an AWS 'Access Token'  if (decodedJWT.payload.token_use != 'access') {     console.log("Not an access token")     rej("Not an access token")  }
  // PART 5: Match the PEM against the request KID  const kid = decodedJWT.header.kid  const pem = pems[kid]  if(!pem){   console.log('Invalid access token')   rej('Invalid access token')  }  console.log("Decoding the JWT with PEM!")
  // PART 6: Verify the signature of the JWT token to ensure its really coming from your User Pool  jwt.verify(jwtToken, pem, {issuer: userPool_Id}, function(err, payload){   if(err){    console.log("Unauthorized signature for this JWT Token")    rej("Unauthorized signature for this JWT Token")   }else{    // if payload exists, then the token is verified!    res(payload)   }  }) }) return p}

Так что это наша Backend Checker Auth. Интегрировать это, перейдите к Example_backend/app/barter.js где мы получаем входящие HTTP-запросы.

// routesconst Authentication = require('./routes/auth_routes');
// router middlewearconst authCheck = require('./api/authCheck').authCheck
module.exports = function(app){ // Auth related routes app.get('/auth_test', authCheck, Authentication.authtest);}

Все, что нам нужно сделать, это добавить его как 2-й аргумент на нашу маршрут Expressjs. Если у вас есть другая бэкэнда, применяется тот же общий процесс.

И вот и это, Backend аутентификация, используя нашу женную среду AWS Cognito. Насколько мощно!

Вывод

Поздравляем для этого длинного учебника на AWS Cognito и Федеративные личности! Завершая это до конца, теперь вы можете насладиться руководством Top-Notch, разработанным крупнейшим в мире поставщиком облачных услуг. Большая часть функциональности, которую вы получаете с AWS, займет недели и множество экспертных знаний для реализации, если вы должны были сделать пользовательскую систему. Ни какая-либо гарантия, которую вы хорошо внедряете пользовательскую систему управления пользовательским управлением, не обнарив своих пользователей на недостатки безопасности и отверстия. Используя Amazon, вы можете отдохнуть ночью, зная, что все, что позаботится о вашей интернет-компании в нескольких миллиардов долларов.

Так что там у нас есть: полная система управления пользователя, готовая к реальному использованию. Если вы думаете, что выиграли или узнали много из этого учебника, пожалуйста, поделитесь и подпишитесь! Я буду публиковать более практичными учебниками AWS в ближайшие месяцы, поэтому обязательно оставаться настроенными. Увидимся в следующий раз!