Цель состоит в том, чтобы создать приложение чата с полным набором функций с использованием умело в реальном времени в сочетании с другими услугами для хранения, манипулирования и обмена данными.
Если у вас есть какие -либо вопросы, идеи или вы хотите внести свой вклад, пожалуйста, поднимите проблему или обратитесь к нам.
Узел 16 установлен
FUNCTIONS FUNCTIONS FUNCTIONS от NPM. Чтобы установить этот запуск:
npm install -g azure-functions-core-tools@4
файл .env в ./api:
JWT_SIGNING_KEY=key used to sign tokens for users. Can be anything you decide it to be
# Ably
ABLY_API_KEY=YOURKEY:HERE
APP_ID=[YOUR ABLY APP ID](https://faqs.ably.com/how-do-i-find-my-app-id)
CONTROL_KEY=[YOUR ABLY CONTROL KEY](https://ably.com/documentation/control-api#authentication)
# Azure
COSMOS_ENDPOINT=https://yourcosomsdb.documents.azure.com
COSMOS_KEY=ASK FOR THIS OR MAKE YOUR OWN
COSMOS_DATABASE_ID=metadata
AZURE_STORAGE_CONNECTION_STRING=your string here
AZURE_STORAGE_CONTAINER_NAME=container name here
# Auth0
AUTH0_DOMAIN=yourdomain.auth0.com
AUTH0_CLIENTID=yourclientid
AUTH0_REDIRECT_URI=http://localhost:8080/auth0-landing
# from root folder
npm run init # installs node modules for api & integrations
npm run start # runs the dev serverКак видно в файле .env, есть несколько услуг, которые вам нужно подписать, чтобы использовать проект в его текущей форме.
Чтобы получить умелые учетные данные, вам сначала необходимо подписаться на бесплатную учетную запись. После того, как у вас есть умелая учетная запись, вы можете перейти в сгенерированное приложение по умолчанию и получить для него ключ Root API. Это будет использоваться для среды ABLY_API_KEY . Перед FullStop переменная APP_ID должна быть установлена на первую часть вашего ключа API. Если ваш ключ API- 12345.jh40fj23jkd0-,32c3-j- , вы должны установить его на 12345 .
Для CONTROL_KEY , который используется для управления созданием клавиш API, приложений и более программы, вам нужно будет перейти к токену Access в качестве зарегистрированного пользователя и нажать «Создать новый токен доступа». Дайте ему имя из выпадающей учетной записи «Учетная запись». Выберите учетную запись, в которой есть приложение, для которого у вас есть ключ API, и обязательно выберите « read:key и write:key . Создайте токен и используйте его значение в качестве CONTROL_KEY .
COSMOSDB используется для хранения данных для этого приложения. Чтобы получить учетную запись Azure и создать ресурс CosmosDB, выполните шаги в учебном пособии Azure. Вы должны установить COSMOS_ENDPOINT на URI, предоставленное в вашем новом Subaccount. COSMOS_KEY является основным ключом для учетной записи CosmoSDB, к которой вы можете получить доступ, как описано Azure.
COSMOS_DATABASE_ID - это имя контейнера, который вы будете использовать в своей учетной записи COSMOSDB.
Используя ту же учетную запись Azure, созданную для CosmoSDB, создайте новый контейнер для хранения данных. После того, как вы получите эту настройку, перейдите в раздел «Ключи доступа» в боковой панели, чтобы получить connection string для AZURE_STORAGE_CONNECTION_STRING , а затем установите AZURE_STORAGE_CONTAINER_NAME , что вы называете контейнером.
Если вы хотите включить Auth0 в качестве метода аутентификации, вам нужно будет создать учетную запись Auth0. После того, как у вас есть учетная запись Auth0, создайте приложение с «обычными веб -приложениями», выбранными в качестве типа приложения. В этом приложении вы можете скопировать домен для AUTH0_DOMAIN и ClientId для AUTH0_CLIENTID . AUTH0_REDIRECT_URI должен указывать на соответствующий URI, который Auth0 после аутентификации пользователя должен перенаправить на. Значение по умолчанию должно работать для работы локально.
На вкладке «Настройки приложения Auth0» прокрутите вниз к разделу «Приложение Uris». В нем вы должны увидеть поле для «разрешенных URL -адресов обратного вызова» и «разрешенных URL -адресов. Для контекста поток веб -страницы с использованием Auth0:
Ваш сайт связывает пользователя на страницу входа в приложение Auth0, где они вводят на страницу страницы Auth0 перенаправление пользователя обратно на страницу «обратный вызов вашего веб -сайта», когда пользователь хочет выйти из системы, он направлен на страницу выхода приложения Auth0, а затем перенаправлен на страницу, указанную на «returnto», передава
Чтобы избежать потенциального неправильного использования и злоупотребления, вам необходимо указать, к чему может перенаправить URL Auth0. При разыгрывании этого приложения для чата локально он размещен на Localhost: 8080, поэтому установите разрешенные URL-адреса обратного вызова на 'http: // localhost: 8080/auth0-lending'. Когда пользователь выйдет в систему, у нас будет перенаправлен пользователь обратно на нашу главную страницу, поэтому установите разрешенные URL -адреса в системе выхода на 'http: // localhost: 8080/'.
Приложение чата состоит из следующего:
Archive API для получения событий от умелого реактора и поддержания истории чатаChat Archive . Приложение React - это приложение по умолчанию, одностраничное приложение. Он использует смесь react-router-dom и пользовательского AppProvider для предоставления контекста безопасности для приложения.
В приложении используются @умелые лабилы/реакционные крючки для взаимодействия с ловкими каналами , а приложение состоит из современных функциональных компонентов реагирования .
Snowpack - это сервер разработки, который прозрачно создаст код ES6 для производства.
BFF - это специфический API приложения , который содержит всю логику сервер для приложения чата. Поскольку он размещен в Azure Static Web Apps , мы можем использовать azure-functions-core-tools запускающую API-сервер.
В дополнение к этому, время выполнения Azure Static Web Apps будет автоматической API для нас, поэтому нам не нужно беспокоиться о настройке хостинга. BFF выполняется на Server Infrastrucutre, а Azure SWA будет автоматически масштабировать его для удовлетворения спроса.
Чтобы добавить новые конечные точки API, вам нужно будет добавить новый каталог в папку api .
Во -первых, создайте каталог для нового API - например, api/messages . Затем создайте файл function.json в новом каталоге.
{
"bindings" : [
{
"route" : " messages " ,
"authLevel" : " function " ,
"type" : " httpTrigger " ,
"direction" : " in " ,
"name" : " req " ,
"methods" : [ " get " , " post " ]
},
{
"type" : " http " ,
"direction" : " out " ,
"name" : " res "
}
],
"scriptFile" : " ../dist/messages/index.js "
} Далее вам нужно создать свой API TypeScript :
import "../startup" ;
import { Context , HttpRequest } from "@azure/functions" ;
export default async function ( context : Context , req : HttpRequest ) : Promise < void > {
context . res = { status : 200 , body : "I'm an API" } ;
} Этот API теперь будет установлен по адресу http://localhost:8080/api/messages .
И это все! Инструмент и SDK будут автоматически определять ваш код при его изменении и восстановить свои функции для вас.
Приложение использует аутентификацию токена JWT между веб -приложением и BFF. Мы храним учетные данные пользователя и соленые, односторонние хэшируемые пароли (сделанные с BCRYPT) в базе данных CosMOSDB.
Когда пользователь аутентифицирует, приложение подписывает токен JWT с идентификатором пользователя и имени пользователя, который затем отправляется в BFF в последующих запросах на аутентифицированные данные. Это означает, что с небольшим количеством кода в API мы можем убедиться, что пользователь является тем, кем он утверждает, и что он имеет право на доступ к данным API.
Мы можем расширить эту модель, чтобы включить коллекцию roles для аутентификации на основе претензий для ресурсов в приложении.
Authenticated User Only Мы можем создать вызов API -сигнала JWT token используя следующие методы удобства в BFF API .
import "../startup" ;
import { Context , HttpRequest } from "@azure/functions" ;
import { authorized , ApiRequestContext } from "../common/ApiRequestContext" ;
export default async function ( context : Context , req : HttpRequest ) : Promise < void > {
await authorized ( context , req , ( ) => {
// This code will only run if the user is authenticated
context . res = {
status : 200 ,
body : JSON . stringify ( "I am validated and authenticated" )
} ;
} ) ;
}Если вы хотите получить доступ к информации пользователей аутентификации как часть одного из этих вызовов API, вы можете сделать следующее:
import "../startup" ;
import { Context , HttpRequest } from "@azure/functions" ;
import { authorized , ApiRequestContext } from "../common/ApiRequestContext" ;
export default async function ( context : Context , req : HttpRequest ) : Promise < void > {
await authorized (
context ,
req ,
( { user } : ApiRequestContext ) => {
// user is the userDetails object retrieved from CosmosDb
context . res = {
status : 200 ,
body : JSON . stringify ( "I am validated and authenticated" )
} ;
} ,
true
) ; // <- true to include the userDetails object in the ApiRequestContext
} Аутентификация в приложении реализована в AppProviders.jsx .
Он предоставляет крюк React, который вернет объект userDetails , если пользователь будет аутентифицирован (наряду с обеспечением того, чтобы пользователь был аутентифицирован вообще). Если данный пользователь не будет аутентифицирован, он будет перенаправлен на страницу входа во все случаи.
Поскольку AppProvider заботится об аутентификации, вам нужно использовать крючки для доступа к пользовательским данным и для выполнения аутентифицированных вызовов API в любых компонентах.
Вот пример доступа к объекту userDetails к нему аутентифицированному пользователю.
import { useAuth } from "../../AppProviders" ;
const MyComponent = ( ) => {
const { user } = useAuth ( ) ;
return < div > { user . username } </ div > ;
} ;
export default MyComponent ; Вы также можете получить доступ к экземпляру класса BffApiClient , который позволит вам сделать аутентифицированные вызовы API и уже содержит в настоящее время регистрируемые пользователи JWT token .
import { useAuth } from "../../AppProviders" ;
const MyComponent = ( ) => {
const { api } = useAuth ( ) ;
const [ channels , setChannels ] = useState ( [ ] ) ;
useEffect ( ( ) => {
const fetchChannels = async ( ) => {
const response = await api . listChannels ( ) ;
setChannels ( response . channels ) ;
} ;
fetchChannels ( ) ;
} , [ ] ) ;
return < div > ... bind channel data here </ div > ;
} ;
export default MyComponent ; Приведенный выше пример использует крюк useEffect для извлечения каналов, когда компонент крепления - запрос API выполняется с использованием экземпляра api , предоставляемого useAuth Hook.
Это единственный способ, которым вы должны сделать вызовы API в BFF из компонента, так как он гарантирует, что токен JWT является действительным и присутствующим.
Если вы добавляете новые BFF APIs в приложение, вам нужно будет реализовать новую функцию в /app/src/sdk/BffApiClient.js , чтобы сделать ее доступным для ваших компонентов.
Эти вызовы BffApiClient просты и выглядят так:
async listChannels ( ) {
const result = await this . get ( "/api/channels" ) ;
return await result . json ( ) ;
} Некоторый код утилиты в клиенте убедится, что правильный JWT token присутствует при выполнении запроса.
Мы используем CosmoSDB для хранения наших метаданных приложений, потому что это масштабируемая, высокодоступная управляемая база данных, которую нам не приходится администрировать себя. Он может работать в предварительно предоставленном или без серверного режима, помогая сохранять низкие затраты, когда приложение не используется (за счет некоторой производительности).
Мы используем одну базу данных COSMOSDB для хранения всех метаданных, и внутри мы создали коллекцию для каждого типа объекта, которую мы храним.
Например: коллекция User хранит наши пользовательские записи - и может быть запрошена с помощью SQL -подобного синтаксиса. COSMOSDB делает это легко, автоматически индексируя документы JSON.
Каждая из хранимых объектов метаданных имеет id и поле type , и мы используем generic repository ( /api/common/dataaccess/CosmosDbMetadataRepository ) для загрузки и сохранения этих сущностей.
Для локальной разработки вы можете использовать либо облачную версию Cosmos, либо использовать одно из доступных docker container images для запуска локальной копии базы данных.
Мы используем Ably channels для хранения наших сообщений в чате и для того, чтобы продвигать события в наше приложение React. Каждый подключенный пользователь будет получать сообщения для каналов, которые они активно просматривают в режиме реального времени, и мы используем Channel rewind для заполнения последних отправленных сообщений.
Сообщения могут быть corrected с асинкруновым после того, как они были получены - например, для применения фильтрации ненормативной лексики или для исправления ошибок правописания. Эти коррекционные сообщения будут частью потока и применяются задним числом в приложении React. (Дальнейшее развитие этого в более поздних эпосах)
Этот дизайн позволяет нам встать на дополнительные API, которые потребляют эти события, и публиковать свои собственные разработки на каналах для клиентов, на которые можно ответить.
Поскольку умелые события со временем исчезнут, мы собираемся хранить копии входящих событий на каждом канале в нашем Chat Archive через Archive API .
Archive API получит сообщения реактора для всех наших каналов и добавит их к специфическим каналам Azure Storage Blobs . API добавит в один файл, пока не достигнет порога размера (~ 500 КБ), а затем создаст новый файл для последующих сообщений.
Archive API сохранит запись в настоящее время активного архивного файла в Metadata database для каждого канала.
Archive API сможет обновить индекс поиска по мере получения сообщений и архивируется, чтобы позже разоблачить их в поиске.
Тесты записываются в jest с ts-jest используемым для выполнения тестов APIS TypeScript .