Эта статья была первоначально опубликована в блоге разработчиков 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 в своем браузере, вы должны увидеть страницу, подобную этой:
Что нужно знать о 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 .