Статьи

Создайте приложение Preact с аутентификацией

Эта статья была первоначально опубликована в блоге разработчиков Okta . Спасибо за поддержку партнеров, которые делают возможным использование SitePoint.

React — это быстрая и легкая библиотека, которая привела к быстрому внедрению в экосистему SPA (одностраничных приложений). Preact — это еще более легкая и быстрая альтернатива React, весом в 3кб! Для менее сложных приложений это может быть отличным выбором.

В этом руководстве вы создадите базовое приложение Preact с парой страниц и аутентификацией пользователя с помощью виджета входа Okta .

Загрузите ваше приложение с PreactCLI

Чтобы начать проект, вы установите PreactCLI с помощью NPM .

npm install -g preact-cli 

После установки CLI выполните команду, чтобы создать базовое приложение Preact:

 preact create okta-preact-example 

Эта команда будет работать в течение нескольких минут, поддерживая базовое приложение Preact и устанавливая все зависимости. Как только это будет сделано, вы должны увидеть кучу информации в командной строке, информирующей вас о том, что вы можете делать дальше.

Перейдите в каталог приложения.

 cd okta-preact-example 

Затем запустите приложение, просто чтобы убедиться, что все работает как положено.

 npm start 

Вы должны увидеть быстрый запуск сборки, и экран очистится и покажет, что приложение работает по адресу http://localhost:8080 . Когда вы откроете этот URL в своем браузере, вы должны увидеть страницу, подобную этой:

Базовое приложение Preact

Что нужно знать о PreactCLI

Несмотря на то, что приложение, сгенерированное PreactCLI, во многом похоже на приложение React, созданное с помощью create-Reaction-app , и вы даже можете использовать некоторые из плагинов React (например, React-Router ) в своем приложении Preact, есть некоторые существенные различия.

Например, в отличие от ReactCLI, нет способа eject конфигурацию Webpack . Вместо этого Preact рекомендует разработчикам настраивать Webpack, создавая файл с именем preact.config.js , используя помощники по настройке Webpack Preact и экспортируя функции для изменения поведения Webpack.

Несмотря на то, что PreactCLI говорит, что приложение работает по адресу http://0.0.0.0:8080 , используйте http://localhost:8080 . Это то же самое, и когда вы настраиваете свое приложение на информационной панели Okta, вы устанавливаете http://localhost:8080 качестве базового URL-адреса и URL-адреса обратного вызова, так что это просто гарантирует, что вы можете вызывать API-интерфейсы Okta.

Создайте приложение Okta

Теперь, когда у вас есть базовая оболочка приложения, пришло время добавить аутентификацию пользователя. Если у вас его еще нет, создайте бесплатную (навсегда) учетную запись в Okta .

После того, как вы создали учетную запись, перейдите на панель администратора и нажмите «Приложения» в меню страницы. Затем нажмите зеленую кнопку «Добавить приложение», затем зеленую кнопку «Создать новое приложение», чтобы вы увидели модальное окно, например:

Экран создания приложения

Выберите «SPA» из кнопок платформы. Нажмите кнопку «Далее», чтобы создать приложение.

Вы перейдете на страницу «Настройки приложения» мастера создания приложения. Введите «OktaPreactExample» в поле «Имя приложения» и добавьте http://localhost:8080 качестве базового URI и в качестве URI перенаправления входа в систему. Когда вы закончите, ваша форма должна выглядеть следующим образом:

Создать экран интеграции

Вам нужно будет создать пользователя (если у вас его еще нет) и назначить ему новое приложение. Или вы можете войти с учетными данными, которые вы используете для входа в свою учетную запись Okta (администратор).

Установить виджет входа в Okta

Самый простой способ получить аутентификацию Okta в вашем новом приложении Preact — использовать виджет входа Okta. Вы установите его с помощью npm, используя:

 npm install @okta/okta-signin-widget --save 

Вам также необходимо установить preact-router с:

 npm install preact-router --save 

Добавить аутентичный компонент высшего порядка

После этого вам нужно добавить несколько компонентов высшего порядка, чтобы помочь с аутентификацией.

Добавьте файл с именем auth.js в папку /src/lib и добавьте следующий код:

 import {h} from 'preact'; import { route } from 'preact-router'; import OktaSignIn from '@okta/okta-signin-widget/dist/js/okta-sign-in.min.js'; import '@okta/okta-signin-widget/dist/css/okta-sign-in.min.css'; import '@okta/okta-signin-widget/dist/css/okta-theme.css'; class Auth { constructor() { this.login = this.login.bind(this); this.logout = this.logout.bind(this); this.isAuthenticated = this.isAuthenticated.bind(this); this.handleAuthentication = this.handleAuthentication.bind(this); this.widget = new OktaSignIn({ baseUrl: 'https://{yourOktaDomain}.com/', clientId: '{clientId}', redirectUri: 'http://localhost:8080', authParams: { responseType: ['id_token', 'token'], scopes: ['openid', 'email', 'profile'] } }); } isAuthenticated() { // Checks if there is a current accessToken in the TokenManger. return !!this.widget.tokenManager.get('accessToken'); } getCurrentUser(){ return this.widget.tokenManager.get('idToken'); } login() { // Redirect to the login page route('/login/'); } async logout() { this.widget.tokenManager.clear(); await this.widget.signOut(); location = '/'; } handleAuthentication(tokens) { for (let token of tokens) { if (token.idToken) { this.widget.tokenManager.add('idToken', token); } else if (token.accessToken) { this.widget.tokenManager.add('accessToken', token); } } } } // create a singleton const auth = new Auth(); export const withAuth = WrappedComponent => props => <WrappedComponent auth={auth} {...props} />; 

В первой строке кода вы можете сказать что-то другое. Модуль h в Preact — это то, что превращает JSX в элементы DOM . Обычно React использует библиотеку React для генерации операторов React.createElement для создания элементов DOM из JSX. Preact использует библиотеку h чтобы сделать что-то вроде операторов h('div', {class:'something'}, 'Content') чтобы сделать это.

Далее вы импортировали route из preact-router прямо под h import. Это то, что используется Preact для перенаправления в функции login в login . Обратите внимание, что класс Auth является обычной функцией и не расширяет Component . В конструкторе внутренние функции были связаны с контекстом this из класса Auth.

Затем введите свой URL-адрес организации и идентификатор клиента в конфигурации виджета входа Okta. URL вашей организации будет URL-адресом, который вы используете при входе в свою учетную запись Okta (например, http://dev-12345.oktapreview.com), и вы можете получить идентификатор своего клиента на странице свойств приложения на административной панели управления в разделе «Общие». ”Для вашего приложения (очевидно, ваше не будет размыто):

Экран идентификации клиента

Вам также нужно изменить свойство redirectUri на http://localhost:8080 потому что Preact использует порт 8080 вместо 3000 для обычных приложений React.

Функция login просто направляет пользователя на страницу входа в систему, в то время как функция logout из logout очищает токены, сохраненные в менеджере токенов виджета, вызывает signOut для виджета и перенаправляет пользователя в корень приложения.

Наконец, создается одиночный объект класса Auth который будет использоваться всеми компонентами, и передается как подпрограмма с именем auth любому компоненту, в который вы withAuth .

Создать Wraget Wrapper

Создайте файл в папке /src/lib именем OktaSignInWidget.js . Введите код для этого компонента:

 import { h, Component } from 'preact'; export default class OktaSignInWidget extends Component { componentDidMount() { this.widget = this.props.widget; this.widget.renderEl({ el: this.widgetContainer }, this.props.onSuccess, this.props.onError); } componentWillUnmount() { this.widget.remove(); } render() { return <div ref={(div) => { this.widgetContainer = div; }} /> } }; 

Здесь метод componentDidMount визуализирует виджет входа Okta в div в вашем методе рендеринга, а функция componentWillUnmount удаляет виджет.

В методе render есть какой-то странно выглядящий код. Это позволяет вам установить ссылку на текущий элемент в переменную с именем widgetContainer а затем использовать ее в componentDidMount как this.widgetContainer . Аккуратно, а? Спасибо Мэтту Рейблу за то, что он показал мне этот трюк!

Создать компонент перенаправления

В React-Router есть компонент Redirect, а в Preact нет, поэтому он вам понадобится. К счастью, легко создать свой собственный. В папке /src/lib создайте файл с именем Redirect.js и добавьте следующий код:

 import { Component } from 'preact'; export default class Redirect extends Component { componentWillMount() { location = this.props.to.pathname; } render() { return null; } } 

Это просто компонент, который будет перенаправлять на основе переданного ему URL. В этом случае использование будет перенаправлено с использованием механизма window.location , главным образом потому, что вы захотите обновить страницу. Вы также можете просто использовать route(this.props.to.pathname) и позволить маршрутизатору Preact перенаправить пользователя.

Создать компонент входа

Затем создайте папку Login в src/routes . В этой папке создайте файл style.css файл style.css . Это просто следует за тем, как Preact CLI создает компоненты.

В файле index.js создайте компонент Login , обернутый в компонент withAuth . Во-первых, для импорта необходимых модулей:

 import { h, Component } from 'preact'; import Redirect from '../../lib/Redirect'; import OktaSignInWidget from '../../lib/OktaSignInWidget'; import { withAuth } from '../../lib/auth'; 

Запустите компонент, withAuth в него withAuth высшего порядка withAuth , который вы создали ранее, и установите начальное состояние. Здесь у вас будет redirectToReferrer установленный в false по умолчанию.

 export default withAuth(class Login extends Component { state = { redirectToReferrer: false }; } 

В функции жизненного цикла onSuccess onError функции onSuccess и onError и создайте их в своем компоненте.

 componentWillMount() { this.onSuccess = this.onSuccess.bind(this); this.onError = this.onError.bind(this); } onSuccess(tokens) { this.props.auth.handleAuthentication(tokens); this.setState({ redirectToReferrer: true }); } onError(err) { console.log('error logging in', err); } 

Вы заметите, что ваш компонент передает обработку аутентификации обратно компоненту более высокого порядка. Это яркий пример преимуществ компонентов и композиции более высокого порядка в JavaScript.

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

 render({location, auth}, {redirectToReferrer}) { let from; if (location && location.state) { from = location.state; } else { from = { pathname: '/' }; } if (auth.isAuthenticated() || redirectToReferrer) { return <Redirect to={from} />; } return ( <OktaSignInWidget widget={auth.widget} onSuccess={this.onSuccess} onError={this.onError} /> ); } 

Здесь вы заметите, что Preact немного отличается тем, что он дает вам дескрипторы для props и state качестве параметров функции render . Этот код просто использует деструктуризацию этих параметров, чтобы упростить использование location , auth и redirectToReferrer не имея тонны this.props.{whatever} .

Итак, ваш окончательный файл /src/routes/login/index.js будет выглядеть так:

 import { h, Component } from 'preact'; import Redirect from '../../lib/Redirect'; import OktaSignInWidget from '../../lib/OktaSignInWidget'; import { withAuth } from '../../lib/auth'; export default withAuth(class Login extends Component { state = { redirectToReferrer: false }; componentWillMount() { this.onSuccess = this.onSuccess.bind(this); this.onError = this.onError.bind(this); } onSuccess(tokens) { this.props.auth.handleAuthentication(tokens); this.setState({ redirectToReferrer: true }); } onError(err) { console.log('error logging in', err); } render({location, auth}, {redirectToReferrer}) { let from; if (location && location.state) { from = location.state; } else { from = { pathname: '/' }; } if (auth.isAuthenticated() || redirectToReferrer) { return <Redirect to={from} />; } return ( <OktaSignInWidget widget={auth.widget} onSuccess={this.onSuccess} onError={this.onError} /> ); } }) 

Обновить страницу профиля

Теперь, когда у вас есть компонент Login и он использует виджет входа Okta, используйте созданный вами компонент auth и обновите страницу профиля (в /src/routes/profile/index.js ), чтобы дать вам больше информации о пользователь. Вот как должен выглядеть ваш окончательный файл /src/routes/profile/index.js :

 import { h, Component } from 'preact'; import { route } from 'preact-router'; import { withAuth } from '../../lib/auth'; import style from './style'; export default withAuth(class Profile extends Component { constructor(props){ super(props); } componentWillMount(){ if(this.props.auth.isAuthenticated()){ this.state = { user: this.props.auth.getCurrentUser() }; }else{ return route('/login/'); } } render(props, { user }) { return ( user ? <div class={style.profile}> <h3 class={style.heading}>Profile</h3> <ul> <li> <span class={style.key}>Name:</span> <span class={style.value}>{user.claims.name}</span> </li> <li> <span class={style.key}>Email:</span> <span class={style.value}>{user.claims.email}</span> </li> </ul> </div> : null ); } }) 

Вы добавили защиту аутентификации на уровне Component в функцию componentWillMount компонента. Если пользователь аутентифицирован, он вызывает функцию getCurrentUser для компонента более высокого порядка и добавляет пользователя в состояние компонента. В функции render вы просто выводите имя пользователя и адрес электронной почты.

Обновите компонент заголовка

Теперь вам просто нужно получить маршруты в ваше приложение и получить меню для ссылки на них. Начните с изменения файла /src/components/header/index.js на:

 import { h, Component } from 'preact'; import { Link } from 'preact-router/match'; import { withAuth } from '../../lib/auth'; import style from './style'; export default withAuth(class Header extends Component { componentWillMount(){ if(this.props.auth.isAuthenticated()){ this.setState({ user: this.props.auth.getCurrentUser() }); } } render(props, {user}) { return ( <header class={style.header}> <h1>Preact App</h1> <nav> <Link activeClassName={style.active} href="/">Home</Link> {user ? <Link activeClassName={style.active} href="/profile">Profile</Link> : null } {user ? <Link activeClassName={style.active} onClick={props.auth.logout.bind(null, props.history)} href="javascript:;">Logout</Link> : <Link activeClassName={style.active} onClick={props.auth.login.bind(null, props.history)} href="javascript:;">Login</Link>} </nav> </header> ); } }) 

Будет показана кнопка «Вход», если пользователь не вошел в систему, и кнопка «Выход», если они есть. Он также покажет пункт меню «Профиль» только тем пользователям, которые вошли в систему.

Измени свой маршрут

Наконец, измените маршруты в файле /src/components/app.js чтобы ваше приложение /src/components/app.js о ваших новых маршрутах и ​​о том, как их обрабатывать. Итак, ваш новый файл app.js будет выглядеть так:

 import { h, Component } from 'preact'; import { Router } from 'preact-router'; import Header from './header'; import Home from '../routes/home'; import Profile from '../routes/profile'; import Login from '../routes/Login'; // import Home from 'async!./home'; // import Profile from 'async!./profile'; export default class App extends Component { /** Gets fired when the route changes. * @param {Object} event "change" event from [preact-router](http://git.io/preact-router) * @param {string} event.url The newly routed URL */ handleRoute = e => { this.currentUrl = e.url; }; render() { return ( <div id="app"> <Header /> <Router onChange={this.handleRoute}> <Home path="/" /> <Profile path="/profile/" /> <Login path="/login/" /> </Router> </div> ); } } 

Все, что действительно изменилось, это то, что вы импортировали недавно созданный компонент Login, удалили пользовательское свойство, передаваемое в компонент Profile, и добавили новый маршрут для компонента Login.

Запустите ваше новое приложение Preact!

Теперь вы сможете сохранить свою работу и запустить npm start в корневой папке и увидеть полнофункциональное приложение Preact с аутентификацией пользователя через Okta!

Есть много общего между Preact и React, но есть некоторые ключевые различия. Preact предназначен для приложений, в которых размер загрузки невелик. В маршрутизаторе Preact есть несколько удобных функций, но некоторые вещи отсутствуют (например, с помощью withRouter ). Есть также некоторые удобные удобства, такие как передача props и state в функцию render . В целом, я думаю, что Preact аккуратен, но я мог видеть, что действительно нужен полноценный React для сложных приложений.

Учить больше

Вы можете узнать больше о Preact на их веб-сайте, а Preact-Router — в репозитории Github .

Вы также можете получить полный код этой статьи из репозитория Okta Developer Github .

Как всегда, если у вас есть какие-либо вопросы, комментарии или сомнения по поводу статьи, кода, Preact или Okta, не стесняйтесь обращаться ко мне по электронной почте или ударить меня в комментариях или через Twitter @leebrandt .