TL;DR: многим приложениям Angular требуется некоторая форма аутентификации для защиты различных разделов приложения. Auth0 — идеальный инструмент для этого. Но что делает эти два замечательных инструмента еще лучше, так это простой способ развертывания приложения, и именно здесь на помощь приходит Netlify. Всего за несколько минут вы можете создать новое приложение Angular, защитить его с помощью Auth0 и развернуть в Netlify. .

Развертывание приложения Angular с Auth0 в Netlify

Auth0 интегрируется со многими языками и фреймворками, и Angular не является исключением. Используя библиотеки, созданные командой Auth0, вы можете защитить свое приложение и быть уверенными, что данные ваших пользователей будут защищены. Сочетание безопасности от Auth0 и защиты маршрута от Angular не позволит пользователям, которые не вошли в систему, получить доступ к конфиденциальным частям вашего приложения.

Как только ваше приложение будет завершено, Netlify станет отличным местом для развертывания этого приложения. Нет необходимости управлять сервером, NGINX, сертификатами или масштабированием из-за высокого трафика. Netlify упрощает автоматическую сборку и развертывание вашего приложения при отправке в определенные ветки, и, что самое приятное, во многих случаях это бесплатно.

Посетите Блог Auth0 🔐 и найдите все, что вам нужно знать об инфраструктуре идентификации, управлении доступом, SSO, аутентификации JWT и последних новостях в Node. 👉 AUTH0 БЛОГ 👈

В этой статье вы создадите приложение Angular, защитите его с помощью Auth0 и защиты маршрута и развернете его в Netlify. Пойдем!

Создать угловой проект

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

npm install -g @angular/cli

Убедившись, что CLI установлен на вашем компьютере, выполните в терминале следующую команду:

ng new my-ng-auth0-netlify --routing --style scss

Эта команда создает новое приложение Angular. Флаг --routing инициирует маршрутизацию в приложении, а флаг --style scss устанавливает для файлов стилей приложения значение SCSS. После запуска команды перейдите в новый каталог и установите загрузчик:

cd my-ng-auth0-netlify npm install bootstrap

Теперь у вас есть новый проект Angular. Включите стили начальной загрузки в файл styles.scss в каталоге src следующим образом:

// src/styles.scss @import '~node_modules/bootstrap/scss/bootstrap.scss';

Замените HTML-код по умолчанию в файле src/app/app.component.html следующим содержимым:

<!-- src/app/app.component.html --> <ul> <li> <a routerLink="/home">Home</a> </li> <li> <a routerLink="/profile">Profile</a> </li> </ul> <div class="container"> <router-outlet></router-outlet> </div>

Теперь ваше приложение настроено для маршрутизации, а настоящая панель навигации будет добавлена ​​позже. Следующее, что вам нужно сделать, это создать компоненты, необходимые для маршрутов в приложении. Для этой демонстрации вы просто создадите два компонента, HomeComponent и ProfileComponent:

ng generate component home ng generate component profile

Добавьте следующее содержимое в шаблон HomeComponent в файле src/app/home/home.component.html:

<!-- src/app/home/home.component.html --> <h1>Welcome to Angular + Auth0 + Netlify</h1> <h3> The home route is not protected and anyone can visit it. The <code>/profile</code> route is protected, though. Log in to see it! </h3>

Затем добавьте следующее содержимое в шаблон ProfileComponent в файле src/app/profile/profile.component.html:

<!-- src/app/profile/profile.component.html --> <h1>Your Auth0 User Profile</h1>

После добавления этого содержимого в эти компоненты зарегистрируйте маршруты в файле AppRoutingModule в файле src/app/app-routing.module.ts.

// src/app/app-routing.module.ts import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; import { ProfileComponent } from './profile/profile.component'; import { HomeComponent } from './home/home.component'; const routes: Routes = [ { path: '', component: HomeComponent, }, { path: 'profile', component: ProfileComponent, }, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule], }) export class AppRoutingModule {}

Теперь у вас есть приложение с двумя компонентами, которые используются в качестве маршрутов. Чтобы убедиться, что все работает правильно, запустите следующую команду в своем терминале, чтобы создать и обслуживать приложение через порт 4200 (порт по умолчанию для приложений Angular):

ng serve --open

Флаг --open откроет ваш браузер на http://localhost:4200 после сборки приложения и запуска сервера разработки. Теперь вы должны иметь возможность перемещаться между домашней страницей и страницей профиля. Позже вы заблокируете страницу профиля, чтобы ее можно было посетить только после входа в систему с помощью Auth0.

Защитите приложение с помощью Auth0

Чтобы защитить приложение с помощью Auth0, сначала необходимо создать приложение в панели управления Auth0. Если у вас нет учетной записи Auth0, вы можете зарегистрироваться на бесплатную. После входа в систему нажмите кнопку Создать приложение в правом верхнем углу.

В появившемся модальном окне назовите свое приложение и выберите тип, в данном случае «Одностраничные веб-приложения»:

Теперь ваше приложение создано на Auth0. Прежде чем вернуться к работе с приложением, вам нужно добавить URL-адрес обратного вызова, который приложение Auth0 распознает и будет использовать для аутентификации вашего приложения при его запуске на локальном хосте. Вы можете добавить URL-адрес обратного вызова в поле «Разрешенные URL-адреса обратного вызова» на вкладке настроек приложения Auth0. Значение, которое вы должны начать в этом поле, равно http://localhost:4200/callback. После развертывания в Netlify вы добавите еще один обратный вызов для развернутого приложения.

Следующим шагом будет добавление аутентификации в ваше приложение Angular. Начните с добавления SDK Auth0 через npm с помощью следующей команды:

npm install @auth0/auth0-spa-js

После установки создайте службу Angular с именем AuthService, например:

ng generate service auth

Откройте этот новый AuthService, расположенный в файле src/app/auth.service.ts, и добавьте в него следующее содержимое:

// src/app/auth.service.ts import { Injectable } from '@angular/core'; import createAuth0Client from '@auth0/auth0-spa-js'; import Auth0Client from '@auth0/auth0-spa-js/dist/typings/Auth0Client'; import { from, of, Observable, BehaviorSubject, combineLatest, throwError } from 'rxjs'; import { tap, catchError, concatMap, shareReplay } from 'rxjs/operators'; import { Router } from '@angular/router'; @Injectable({ providedIn: 'root', }) export class AuthService { // Create an observable of Auth0 instance of client auth0Client$ = (from( createAuth0Client({ domain: 'YOUR_AUTH0_DOMAIN', client_id: 'YOUR_AUTH0_APP_CLIENT_ID', redirect_uri: `${window.location.origin}/callback`, }), ) as Observable<Auth0Client>).pipe( shareReplay(1), // Every subscription receives the same shared value catchError(err => throwError(err)), ); // Define observables for SDK methods that return promises by default // For each Auth0 SDK method, first ensure the client instance is ready // concatMap: Using the client instance, call SDK method; SDK returns a promise // from: Convert that resulting promise into an observable isAuthenticated$ = this.auth0Client$.pipe( concatMap((client: Auth0Client) => from(client.isAuthenticated())), tap(res => (this.loggedIn = res)), ); handleRedirectCallback$ = this.auth0Client$.pipe( concatMap((client: Auth0Client) => from(client.handleRedirectCallback())), ); // Create subject and public observable of user profile data private userProfileSubject$ = new BehaviorSubject<any>(null); userProfile$ = this.userProfileSubject$.asObservable(); // Create a local property for login status loggedIn: boolean = null; constructor(private router: Router) { } // When calling, options can be passed if desired // https://auth0.github.io/auth0-spa-js/classes/auth0client.html#getuser getUser$(options?): Observable<any> { return this.auth0Client$.pipe( concatMap((client: Auth0Client) => from(client.getUser(options))), tap(user => this.userProfileSubject$.next(user)), ); } localAuthSetup() { // This should only be called on app initialization // Set up local authentication streams const checkAuth$ = this.isAuthenticated$.pipe( concatMap((loggedIn: boolean) => { if (loggedIn) { // If authenticated, get user and set in app // NOTE: you could pass options here if needed return this.getUser$(); } // If not authenticated, return stream that emits 'false' return of(loggedIn); }), ); checkAuth$.subscribe((response: { [key: string]: any } | boolean) => { // If authenticated, response will be user object // If not authenticated, response will be 'false' this.loggedIn = !!response; }); } login(redirectPath: string = '/') { // A desired redirect path can be passed to login method // (e.g., from a route guard) // Ensure Auth0 client instance exists this.auth0Client$.subscribe((client: Auth0Client) => { // Call method to log in client.loginWithRedirect({ redirect_uri: `${window.location.origin}/callback`, appState: { target: redirectPath }, }); }); } handleAuthCallback() { // Only the callback component should call this method // Call when app reloads after user logs in with Auth0 let targetRoute: string; // Path to redirect to after login processsed const authComplete$ = this.handleRedirectCallback$.pipe( // Have client, now call method to handle auth callback redirect tap(cbRes => { // Get and set target redirect route from callback results targetRoute = cbRes.appState && cbRes.appState.target ? cbRes.appState.target : '/'; }), concatMap(() => { // Redirect callback complete; get user and login status return combineLatest(this.getUser$(), this.isAuthenticated$); }), ); // Subscribe to authentication completion observable // Response will be an array of user and login status authComplete$.subscribe(([user, loggedIn]) => { // Redirect to target route after callback processing this.router.navigate([targetRoute]); }); } logout() { // Ensure Auth0 client instance exists this.auth0Client$.subscribe((client: Auth0Client) => { // Call method to log out client.logout({ client_id: 'YOUR_AUTH0_APP_CLIENT_ID', returnTo: `${window.location.origin}`, }); }); } }

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

Есть две части предоставленного кода для AuthService, которые вам нужно изменить. Это client_id и domain. Текст заполнителя — YOUR_AUTH0_APP_CLIENT_ID и YOUR_AUTH0_DOMAIN. Вам нужно будет заменить эти значения заполнителей значениями из вкладки настроек приложения Auth0.

Следующим шагом является изменение файла src/app/app.component.ts для настройки аутентификации при перезагрузке приложения. Это необходимо, поскольку при перезагрузке одностраничного приложения все, что хранится в памяти приложения, очищается. Поскольку именно там хранится ваша аутентификационная информация, вы обычно теряете свои аутентификационные данные. Чтобы обойти это, вы вызовете функцию localAuthSetup() из AuthService, чтобы при необходимости можно было восстановить данные. Откройте файл src/app/app.component.ts и добавьте следующее содержимое:

// src/app/app.component.ts import { Component, OnInit } from '@angular/core'; import { AuthService } from './auth.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'], }) export class AppComponent implements OnInit { constructor(private auth: AuthService) { } ngOnInit() { this.auth.localAuthSetup(); } }

Теперь добавьте компонент навигационной панели:

ng generate component navbar

Откройте файл src/app/navbar/navbar.component.ts и добавьте в него следующее содержимое:

// src/app/navbar/navbar.component.ts import { Component, OnInit } from '@angular/core'; import { AuthService } from '../auth.service'; @Component({ selector: 'app-navbar', templateUrl: './navbar.component.html', styleUrls: ['./navbar.component.css'], }) export class NavbarComponent implements OnInit { constructor(public auth: AuthService) { } ngOnInit() { } }

В файле HTML для NavbarComponent добавьте следующее:

<!-- src/app/navbar/navbar.component.ts --> <nav class="navbar navbar-expand-lg navbar-light bg-light"> <a class="navbar-brand" routerLink="/">Auth0 + Netlify</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation" > <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav"> <li class="nav-item active"> <a class="nav-link" routerLink="/">Home</a> </li> <li class="nav-item"> <a class="nav-link" routerLink="/profile">Profile</a> </li> <li class="nav-item"> <button class="btn btn-primary" (click)="auth.login()" *ngIf="!auth.loggedIn">Log In</button> </li> <li class="nav-item"> <button class="btn btn-primary" (click)="auth.logout()" *ngIf="auth.loggedIn">Log Out</button> </li> </ul> </div> </nav>

Добавьте этот NavbarComponent в файл src/app/app.component.html над router-outlet, удалив ul, который был там раньше для временной маршрутизации:

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

ng generate component callback

В файле src/app/callback/callback.component.ts добавьте следующий код:

// src/app/callback/callback.component.ts import { Component, OnInit } from '@angular/core'; import { AuthService } from '../auth.service'; @Component({ selector: 'app-callback', templateUrl: './callback.component.html', styleUrls: ['./callback.component.css'], }) export class CallbackComponent implements OnInit { constructor(private auth: AuthService) {} ngOnInit() { this.auth.handleAuthCallback(); } }

Вызов функции handleAuthCallback() в этом CallbackComponent гарантирует, что пользователь вошел в систему и данные сохранены. Добавьте этот компонент в свой файл src/app/app-routing.module.ts, чтобы приложение знало о нем:

// src/app/app-routing.module.ts const routes: Routes = [ ..., { path: 'callback', component: CallbackComponent } ];

Затем обновите шаблон компонента профиля, чтобы вывести информацию профиля вошедшего в систему пользователя. Замените содержимое файла src/app/profile/profile.component.ts следующим:

// src/app/profile/profile.component.ts import { Component, OnInit } from '@angular/core'; import { AuthService } from '../auth.service'; @Component({ selector: 'app-profile', templateUrl: './profile.component.html', styleUrls: ['./profile.component.css'], }) export class ProfileComponent implements OnInit { constructor(public auth: AuthService) {} ngOnInit() {} }

Затем добавьте в файл src/app/profile/profile.component.html следующее, оставив тег h1 в шаблоне:

На этом этапе у вас настроена аутентификация с маршрутом профиля, возможностью входа и выхода, а также восстановлением статуса аутентификации при загрузке приложения. Но единственная проблема заключается в том, что вы можете перейти на маршрут /profile до того, как войдете в систему. Вы не хотите, чтобы это произошло, поэтому затем вы добавите защиту маршрута, чтобы предотвратить это. Создайте защиту маршрута с помощью Angular CLI:

ng generate guard auth

Вы должны увидеть приглашение с вопросом, какие интерфейсы вы хотели бы реализовать. Выберите CanActivate и продолжите. После создания защиты откройте файл src/app/auth.guard.ts и замените его содержимое следующим:

// src/app/auth.guard.ts import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, CanActivate } from '@angular/router'; import { Observable } from 'rxjs'; import { AuthService } from './auth.service'; import { tap } from 'rxjs/operators'; @Injectable({ providedIn: 'root', }) export class AuthGuard implements CanActivate { constructor(private auth: AuthService) {} canActivate( next: ActivatedRouteSnapshot, state: RouterStateSnapshot, ): Observable<boolean> | Promise<boolean | UrlTree> | boolean { return this.auth.isAuthenticated$.pipe( tap(loggedIn => { if (!loggedIn) { this.auth.login(state.url); } }), ); } }

Последний шаг — добавить охрану на маршрут /profile. Откройте файл src/app/app-routing.module.ts и измените определение маршрута /profile на следующее:

// src/app/app-routing.module.ts const routes: Routes = [ ..., { path: 'profile', component: ProfileComponent, canActivate: [AuthGuard] }, ... ]

Это добавляет AuthGuard к этому маршруту, а это означает, что если служба AuthGuard возвращает true при вызове, пользователь сможет продолжить маршрут. Если он возвращает false, они будут перенаправлены для входа в систему.

Теперь вы должны быть в состоянии обслуживать свое приложение и опробовать его. Если у вас возникнут какие-либо проблемы, вернитесь к шагам, описанным выше, или ознакомьтесь с полным кратким руководством на сайте Auth0.

Теперь у вас есть приложение Angular до такой степени, что его можно отправить на GitHub. Добавьте и зафиксируйте все свои файлы. Через минуту вы отправите проект на GitHub.

git add . git commit -m "My Angular + Auth0 + Netlify project"

Конфигурация перенаправления Netlify

Перед отправкой кода в репозиторий GitHub вам необходимо настроить перенаправления Netlify для работы с вашим приложением. В одностраничных приложениях, таких как те, которые вы можете создать с помощью Angular, маршрутизация обрабатывается самим приложением, а не путем перенаправления на новые страницы на реальном сервере. Таким образом, приложение может маршрутизироваться, пока вы не обновите приложение. Если вы обновите приложение на любой странице, кроме пустого маршрута, Netlify не сможет найти маршрут. Вы можете исправить это, сообщив Netlify, где найти каждый маршрут в вашем приложении. По сути, каждый маршрут будет отправлен обратно в приложение Angular, сообщив Netlify, что на самом деле все маршруты нужно просто отправить в файл index.html приложения.

Все, что Netlify будет ожидать от этого, — это файл _redirects в корне развернутого приложения. Содержимое этого файла должно быть:

# src/_redirects /* /index.html 200

Опять же, это просто говорит Netlify, что каждый маршрут должен просто возвращать файл src/index.html. Таким образом, Angular может обрабатывать маршрутизацию.

После добавления файла необходимо убедиться, что он включен в сборку. Самый простой способ сделать это — отредактировать файл angular.json. Если добавить путь к этому файлу (src/_redirects) в массив assets по favicon.ico, он будет включен в сборку приложения.

{ ... "projects": { "my-ng-auth0-netlify": { ... "architect": { "build": { ... "options": { ... "assets": ["src/favicon.ico", "src/_redirects", "src/assets"], ... }, ... } }, ... } } ... }

Создайте репозиторий GitHub

Теперь пришло время перейти на GitHub и создать новый репозиторий.

Запустите следующие команды в своем терминале, которые отправят ваш проект Angular во вновь созданный репозиторий GitHub:

git remote add origin [email protected]:pjlamb12/my-ng-auth0-netlify-project.git git push -u origin master

Не забудьте заменить [email protected]:pjlamb12/my-ng-auth0-netlify-project.git на URL-адрес, предоставленный вам GitHub

Ваш проект теперь в репозитории GitHub!

Настройте Netlify для сборки и развертывания вашего приложения

Следующим шагом является настройка Netlify для сборки и развертывания вашего приложения. Вам нужно будет подключить новый репозиторий GitHub к Netlify и выбрать параметры сборки. После этого Netlify будет собирать и развертывать ваше приложение каждый раз, когда обновления отправляются в основную ветку. Перейдите на app.netlify.com и приступайте к работе.

Если вы еще не зарегистрировались в Netlify, выполните шаги по созданию учетной записи. Это бесплатно, и вы можете легко зарегистрироваться с помощью своей учетной записи GitHub.

После входа в систему нажмите кнопку «Новый сайт из Git» на странице. Вы должны увидеть этот экран после нажатия на эту кнопку:

Выберите поставщика git для непрерывного развертывания, которым может быть GitHub, если вы следите за ним. После выбора GitHub вам может потребоваться установить приложение Netlify для GitHub и авторизовать его в своей учетной записи. Сделав это, вы можете найти репозиторий, в котором находится ваш проект (my-ng-auth0-netlify).

Netlify позволяет вам выбрать команду (если вы являетесь частью более чем одной) и какую ветку следует использовать для сборки. Для команды сборки введите ng build --prod. Если у вас есть другая конфигурация, которую вы используете помимо рабочей, вы можете изменить эту команду сборки, используя флаг --configuration. Прежде чем нажимать кнопку развертывания сайта, обязательно введите расположение каталога публикации. По умолчанию каталог публикации находится в папке dist/project-name. В вашем случае это dist/my-ng-auth0-netlify. Введите это в поле, а затем нажмите кнопку развертывания сайта.

После заполнения этой формы и нажатия кнопки «Развернуть сайт» Netlify перенаправит вас на страницу обзора проекта. Вы должны увидеть сообщение в верхней части страницы о том, что приложение развертывается. Вы также можете щелкнуть пункт меню «Развертывания» и выбрать самый последний, чтобы следить за ходом сборки.

На странице обзора также есть автоматически сгенерированный идентификатор сайта. Этот идентификатор сайта будет частью того, как вы сможете получить доступ к сайту. Будет создан URL-адрес site-id.netlify.com. На изображении выше вы можете видеть, что автоматически сгенерированный идентификатор сайта был «sad-fermi-0e08cb». Вы можете изменить это имя сайта на странице настроек, в разделе общей информации. Единственным требованием является уникальность имени. Изменение имени поможет вам запомнить, где находится ваш сайт. Вы также можете перейти в раздел «Управление доменом» в настройках сайта и настроить собственное доменное имя для сайта.

Еще одна вещь, которую вам нужно будет сделать после того, как вы окончательно определились с именем своего сайта (будь то личный домен, изменение автоматически сгенерированного идентификатора сайта или использование автоматически сгенерированного идентификатора сайта), — это добавить URL-адрес в качестве URL-адреса обратного вызова в настройках Auth0. для вашего приложения. Без этого вы не сможете войти в систему. Вы добавите это в то же место, где вы добавили http://localhost:4200 в качестве обратного вызова. Это на странице настроек приложения Auth0.

Как только ваше приложение будет завершено и развернуто, посетите сайт и убедитесь, что вы можете войти в систему, используя Auth0, и что вы можете перемещаться между домашней страницей и страницей профиля. Он должен работать так же, как сайт на вашем локальном компьютере. Вы должны быть в состоянии начать с домашней страницы и переключаться между домашней ссылкой и ссылкой на профиль. Довольно здорово, да?

Вывод

Netlify — это недорогой и простой способ развертывания приложений Angular, а с помощью такого сервиса, как Auth0, вы также можете ограничить доступ к приложению. С такими инструментами, как Функции Netlify, вы можете создать полноценное приложение без необходимости управлять серверами или сложными процессами сборки. Это идеальный вариант для компаний, которые только начинают работу и не имеют возможности управлять серверами. Вы можете найти репозиторий со всем необходимым рабочим кодом для этой демонстрации здесь. Это приложение развернуто на Netlify и доступно по адресу pjlamb12.ng-auth0.netlify.com.

О Auth0

Auth0, платформа идентификации для разработчиков приложений, предоставляет тысячам клиентов в каждом секторе рынка единственное решение для идентификации, необходимое им для их веб-приложений, мобильных приложений, IoT и внутренних приложений. Его расширяемая платформа легко аутентифицирует и защищает более 2,5 миллиардов входов в систему в месяц, что делает ее любимой разработчиками и надежной компанией со всего мира. Штаб-квартира компании в США в Белвью, штат Вашингтон, и дополнительные офисы в Буэнос-Айресе, Лондоне, Токио и Сиднее обслуживают своих глобальных клиентов, которые находятся в более чем 70 странах.

Для получения дополнительной информации посетите https://auth0.com или подпишитесь на @auth0 в Twitter.

Первоначально опубликовано на https://auth0.com.