Аутентификация Angular с JWT
Russian (Pусский) translation by Masha Kolesnikova (you can also view the original English article)
Безопасность является важной частью каждого веб-приложения, и разработчики должны убедиться, что они разрабатывают приложения с безопасной аутентификацией. В этом руководстве вы узнаете, как реализовать аутентификацию на основе JWT в приложениях Angular с помощью простого сервера Express.
Полный код можно найти в нашем репозитории GitHub. Приложение, которое мы будем создавать, будет выглядеть так:



Концепция веб-токенов JSON
JSON Web Token (JWT) - это в основном объект, представленный тремя строками, которые используются для передачи пользовательской информации. Три строки, разделенные точками:
- заголовок
- полезная нагрузка
- подпись
Когда пользователь входит на любую веб-страницу со своим именем пользователя и паролем, сервер аутентификации обычно создает и отправляет обратно JWT. Затем этот JWT передается вместе с последующими вызовами API на сервер. JWT остается в силе, пока не истечет срок его действия или пользователь не выйдет из приложения.
Этот процесс может быть проиллюстрирован на диаграмме ниже.



Файлы cookie и локальное хранилище
Мы будем использовать локальное хранилище для хранения токенов. Локальное хранилище - это средство, с помощью которого данные хранятся локально и могут быть удалены только через JavaScript или путем очистки кэша в браузере. Данные, хранящиеся в локальном хранилище, могут сохраняться очень долго. С другой стороны, файлы cookie - это сообщения, которые отправляются с сервера в браузер и имеют ограниченное хранилище.
Создание Express сервера
Мы начнем с создания внутреннего сервера, который будет иметь следующие конечные точки:
- POST <webservice>/login
- POST <webservice>/profile
Давайте начнем с создания каталога для приложения Express, а затем запустим команду npm init, чтобы установить необходимые файлы для проекта.
1 |
mkdir server
|
2 |
cd server
|
3 |
npm init |
Затем создайте файл server.js и установите модули: express, jsonwebtoken, cors и bodyParser.
1 |
touch server.js
|
2 |
npm install express jsonwebtoken cors bodyParser –save
|
Теперь откройте server.js и начните с импорта модулей.
1 |
// server.js
|
2 |
const cors = require('cors'); |
3 |
const bodyParser = require('body-parser'); |
4 |
const jwt = require('jsonwebtoken'); |
5 |
const express = require('express'); |
Затем создайте приложение Express и определите секретный ключ, который будет использоваться для кодирования и декодирования данных пользователя.
1 |
//CREATE EXPRESS APP
|
2 |
const app = express(); |
3 |
app.use(cors()); |
4 |
app.use(bodyParser.json()); |
5 |
|
6 |
// DECLARE JWT-secret
|
7 |
const JWT_Secret = 'your_secret_key'; |
Мы не будем использовать базу данных для этого примера. Тем не менее, концепции были бы похожи, если бы вы писали правильный сервер с поддержкой базы данных.
В нашем примере мы просто будем использовать переменную для определения тестового пользователя, как показано ниже.
1 |
var testUser = { email: 'kelvin@gmai.com', password: '1234'}; |
Последний шаг - создание маршрутов для аутентификации пользователя.
1 |
app.post('/api/authenticate', (req, res) => { |
2 |
|
3 |
if (req.body) { |
4 |
var user = req.body; |
5 |
console.log(user) |
6 |
|
7 |
if (testUser.email===req.body.email && testUser.password === req.body.password) { |
8 |
var token = jwt.sign(user, JWT_Secret); |
9 |
res.status(200).send({ |
10 |
signed_user: user, |
11 |
token: token |
12 |
});
|
13 |
} else { |
14 |
res.status(403).send({ |
15 |
errorMessage: 'Authorisation required!' |
16 |
});
|
17 |
}
|
18 |
} else { |
19 |
res.status(403).send({ |
20 |
errorMessage: 'Please provide email and password' |
21 |
});
|
22 |
}
|
23 |
|
24 |
});
|
Давайте разберем код для маршрута выше.
Сначала мы проверяем, есть ли какие-либо данные в теле запроса. Если данные не найдены, мы предлагаем пользователю ввести некоторые данные. В случае, когда пользователь предоставил правильные данные, мы сравниваем их с данными из testUser и, если они совпадают, мы используем идентификатор пользователя, чтобы сгенерировать уникальный токен и отправить ответ пользователю.
Наконец, мы создаем конечную точку для запуска приложения.
1 |
app.listen(5000, () => console.log('Server started on port 5000')); |
Наш бэкэнд теперь готов, и вы можете протестировать его с помощью Postman или CURL и посмотреть, какие данные будут возвращены пользователю.
Создайте приложение Angular
Наше приложение Angular будет содержать следующие страницы:
- Главная страница - эта страница будет содержать ссылки на страницы входа и профиля.
- Логин - на этой странице пользователь введет свой адрес электронной почты и пароль, которые будут отправлены на сервер для аутентификации. Если учетные данные верны, то будет возвращен токен JWT, и пользователь будет перенаправлен на страницу профиля.
- Профиль - это защищенная страница, доступ к которой может получить только пользователь с действительным токеном.
Создайте приложение Angular и создайте компоненты Login и Profile, как показано ниже:
1 |
ng new angular6jwt |
2 |
cd angular6jwt
|
3 |
ng g component Login |
4 |
ng g component Profile |
Затем добавьте код для домашней страницы в app.component.html.
1 |
<!--The content below is only a placeholder and can be replaced.-->
|
2 |
<div style="text-align:center"> |
3 |
<ul>
|
4 |
<li><a class="nav-link" routerLink="/" routerLinkActive="active">Home</a> </li> |
5 |
<li><a class="nav-link" routerLink="profile" routerLinkActive="active">Profile</a> </li> |
6 |
<li style="float:right" > <a class="nav-link" style="float:right" routerLink="login" routerLinkActive="active">Login</a> </li> |
7 |
<li style="float:right" > <a class ="nav-link" (click)="logout()" href="#">Logout</a></li> |
8 |
</ul>
|
9 |
<div class="text-center"> |
10 |
<p>
|
11 |
Angular 6 Authentication with JWT Tutorial |
12 |
</p>
|
13 |
</div>
|
14 |
<router-outlet></router-outlet>
|
15 |
Затем импортируйте RouterModule и определите маршруты в app.module.ts.
1 |
import { RouterModule } from '@angular/router'; |
2 |
|
3 |
|
4 |
@NgModule({ |
5 |
declarations: [ |
6 |
AppComponent, |
7 |
LoginComponent, |
8 |
ProfileComponent
|
9 |
],
|
10 |
imports: [ |
11 |
BrowserModule, |
12 |
RouterModule, |
13 |
FormsModule, |
14 |
RouterModule.forRoot([ |
15 |
{ path: '', redirectTo: '/', pathMatch: 'full' }, |
16 |
{ path: 'login', component: LoginComponent }, |
17 |
{ path: 'profile', component: ProfileComponent } |
18 |
|
19 |
|
20 |
]),
|
21 |
],
|
22 |
providers: [], |
23 |
bootstrap: [AppComponent] |
24 |
})
|
25 |
export class AppModule { } |
Создаем страницу входа
Страница входа будет содержать два поля ввода для адреса электронной почты и пароля, а также кнопку отправки, как показано ниже:
1 |
<h3>Login</h3> |
2 |
<div>
|
3 |
<div class="spacer"> |
4 |
<label for="Email">Email</label> |
5 |
<input type="text" placeholder="Email" [(ngModel)]="email"> |
6 |
</div>
|
7 |
<div class="spacer"> |
8 |
<label for="password">Password</label> |
9 |
<input type="password" placeholder="password" [(ngModel)]="password" class="form-control"/> |
10 |
</div>
|
11 |
<div class="spacer"> |
12 |
<button type="submit" (click)="Login()">Login</button> |
13 |
</div>
|
14 |
</div>
|
Создаем страницу профиля
Страница профиля будет просто сообщением, как показано ниже:
1 |
<p>
|
2 |
If you can see this page, you are logged in! |
3 |
</p>
|
Авторизация с JWT в Angular
Мы начнем с создания сервиса Auth, который облегчит проверку ввода пользователя и взаимодействия с сервером.
1 |
// Create authentication service named Auth
|
2 |
ng g service Auth |
Это создает два файла, но в основном нас заинтересует файл auth.service.ts, в который мы напишем весь код, взаимодействующий с сервером. Мы начнем с определения REST API и токена, как показано ниже:
1 |
export class AuthService { |
2 |
|
3 |
api = 'https://localhost:3000/api'; |
4 |
token; |
5 |
|
6 |
}
|
Далее мы напишем код, который выполняет POST-запрос к серверу с учетными данными пользователя. Здесь мы делаем запрос к API - если он успешен, мы сохраняем токен в localStorage и перенаправляем пользователя на страницу профиля.
1 |
import { Injectable } from '@angular/core'; |
2 |
import { HttpClientModule, HttpClient } from '@angular/common/http'; |
3 |
import { Router } from '@angular/router'; |
4 |
|
5 |
@Injectable({ |
6 |
providedIn: 'root' |
7 |
})
|
8 |
|
9 |
export class AuthService { |
10 |
|
11 |
uri = 'http://localhost:5000/api'; |
12 |
token; |
13 |
|
14 |
constructor(private http: HttpClient,private router: Router) { } |
15 |
login(email: string, password: string) { |
16 |
this.http.post(this.uri + '/authenticate', {email: email,password: password}) |
17 |
.subscribe((resp: any) => { |
18 |
|
19 |
this.router.navigate(['profile']); |
20 |
localStorage.setItem('auth_token', resp.token); |
21 |
|
22 |
})
|
23 |
);
|
24 |
|
25 |
}
|
26 |
|
27 |
}
|
Мы также определяем функции входа и выхода из системы, как показано ниже.
1 |
logout() { |
2 |
localStorage.removeItem('token'); |
3 |
}
|
4 |
|
5 |
public get logIn(): boolean { |
6 |
return (localStorage.getItem('token') !== null); |
7 |
}
|
- logout - очищает токен от локального хранилища
- logIn - возвращает логическое свойство, которое определяет, аутентифицирован ли пользователь
Затем мы обновляем свойство logIn на домашней странице, как показано.
1 |
<ul>
|
2 |
<li><a class="nav-link" routerLink="/" routerLinkActive="active">Home</a> </li> |
3 |
<li><a class="nav-link" routerLink="profile" routerLinkActive="active" *ngIf="authService.logIn">Profile</a> </li> |
4 |
<li style="float:right" > <a class="nav-link" style="float:right" routerLink="login" routerLinkActive="active" *ngIf="!authService.logIn">Login</a> </li> |
5 |
<li style="float:right" > <a class ="nav-link" (click)="logout()" href="#" *ngIf="authService.logIn">Logout</a> </li> |
6 |
</ul>
|
Ответ на пользовательские события
Теперь, когда мы закончили с кодом, взаимодействующим с сервером, мы перейдем к обработке пользовательских событий для внешнего интерфейса.
Мы напишем функцию, которая будет прослушивать события щелчка со страницы входа в систему, а затем передавать значения в AuthService для аутентификации пользователя. Обновите файл login.component.ts, чтобы он выглядел следующим образом:
1 |
import { Component, OnInit } from '@angular/core'; |
2 |
import { Router, ActivatedRoute } from '@angular/router'; |
3 |
|
4 |
import { AuthService } from '../auth.service'; |
5 |
|
6 |
@Component({ |
7 |
selector: 'app-login', |
8 |
templateUrl: './login.component.html', |
9 |
styleUrls: ['./login.component.css'] |
10 |
})
|
11 |
export class LoginComponent implements OnInit { |
12 |
email = ''; |
13 |
password = ''; |
14 |
|
15 |
constructor(private authService: AuthService) { |
16 |
|
17 |
}
|
18 |
Login() { |
19 |
console.log("you are logging in") |
20 |
this.authService.login(this.email, this.password) |
21 |
|
22 |
}
|
23 |
|
24 |
ngOnInit() { } |
25 |
}
|
Теперь, если вы запустите ng serve и перейдете по адресу http://localhost:4200, вы можете протестировать свое приложение.
1 |
ng serve |
Нажмите на ссылку для входа и введите учетные данные пользователя. Помните, действительные учетные данные определены в приложении Express. Теперь, когда вы нажмете кнопку входа в систему, вы будете перенаправлены на страницу профиля.
Заключение
Из этого руководства вы узнали, как начать работу с аутентификацией JWT в Angular. Теперь вы можете проходить аутентификацию и авторизацию с помощью JWT в ваших приложениях Angular. Есть много аспектов JWT, которые не были рассмотрены в этом руководстве - посмотрите, можете ли вы изучить некоторые из них самостоятельно!
Обратите внимание, что это руководство было написано для Angular 6, но те же концепции должны работать с Angular 2 или Angular 4.



