В этой статье мы рассмотрим аутентификацию одностраничного приложения (созданного с использованием Vue.js) в Amazon Cognito с использованием протокола OAuth. В нашей предыдущей статье мы интегрировали серверное приложение с Amazon Cognito.
Строительные леса одностраничного приложения
Мы будем использовать vue-cli для создания пустого приложения Vuejs. Vue CLI можно установить, следуя инструкциям здесь .
Давайте создадим пустое приложение под названием aws-cognito-spa-demo
, выполнив следующую команду:
1
|
vue create aws-cognito-spa-demo |
Вам будет предложено выбрать плагины
После того, как приложение было создано, вы можете перейти в этот каталог и выполнить команду для запуска приложения.
1
2
3
|
cd aws-cognito-spa-demo npm instal npm run serve |
Приложение будет запущено по адресу http: // localhost: 8080.
Установка дополнительных зависимостей
Мы установим необходимые пакеты узлов, которые мы будем использовать для приложения:
1
2
3
4
|
npm install --save amazon-cognito-auth-js npm install --save amazon-cognito-identity-js npm install --save vue-router npm install --save axios |
Создание нового клиента приложения в Amazon Cognito
Мы создадим новый клиент приложения под названием test-spa-client
из консоли Amazon Cognito, как показано ниже:
Обновите настройки для созданного клиента, перейдя в «Настройки клиента приложения», указав значения URL-адреса обратного вызова, URL-адреса выхода из системы, разрешенного потока OAUth и областей OAuth:
Мы используем Implicit Grant в качестве потока OAuth для приложений SPA.
Создание переменных среды
Мы будем хранить настройки, связанные с Amazon Cognito, в файлах свойств, а Vue CLI сделает их доступными среди переменных среды во время выполнения приложения. Подробнее об определении переменных среды в приложениях Vue JS можно найти здесь .
Мы будем хранить общие настройки приложения, такие как URI перенаправления cognito, URI
файле .env
и некоторые локальные настройки в .env.local. Файлы .env. *. Local и .env.local игнорируются в git. Таким образом, вы не фиксируете локальные настройки для контроля версий. .env
1
2
3
4
|
# In .env VUE_APP_COGNITO_REDIRECT_URI=http: //localhost:8080/login/oauth2/code/cognito VUE_APP_COGNITO_REDIRECT_URI_SIGNOUT=http: //localhost:8080/logout VUE_APP_APP_URL=http: //localhost:8080 |
Тогда следующее в .env.local:
1
2
3
|
VUE_APP_COGNITO_USERPOOL_ID=<cognito userpool id> VUE_APP_COGNITO_APP_DOMAIN=<cognito app domain> VUE_APP_COGNITO_CLIENT_ID=<app client id> |
Создание пользовательского информационного магазина
Мы будем использовать глобальный объект JSON для хранения зарегистрированной пользовательской информации. Это альтернативный подход к использованию Vuex . Давайте создадим объект JSON в src/app/user-info-store.js
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
var state = { cognitoInfo: {}, loggedIn: false , loadingState: true , errorLoadingState: false } function setLoggedIn(newValue) { state.loggedIn = newValue; } function setLoggedOut() { state.loggedIn = false ; state.cognitoInfo = {}; } function setCognitoInfo(newValue){ state.cognitoInfo = newValue; } export default { state: state, setLoggedIn: setLoggedIn, setLoggedOut: setLoggedOut, setCognitoInfo: setCognitoInfo } |
Оболочка для Amazon Cognito API
Давайте создадим оболочку src/app/auth.js
для Amazon Cognito API, которая облегчит такие операции, как создание объекта CognitoAuth
, login, logout:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
/* eslint-disable */ import {CognitoAuth, StorageHelper} from 'amazon-cognito-auth-js' ; import IndexRouter from '../router/index' ; import UserInfoStore from './user-info-store' ; import UserInfoApi from './user-info-api' ; const CLIENT_ID = process.env.VUE_APP_COGNITO_CLIENT_ID; const APP_DOMAIN = process.env.VUE_APP_COGNITO_APP_DOMAIN; const REDIRECT_URI = process.env.VUE_APP_COGNITO_REDIRECT_URI; const USERPOOL_ID = process.env.VUE_APP_COGNITO_USERPOOL_ID; const REDIRECT_URI_SIGNOUT = process.env.VUE_APP_COGNITO_REDIRECT_URI_SIGNOUT; const APP_URL = process.env.VUE_APP_APP_URL; var authData = { ClientId : CLIENT_ID, // Your client id here AppWebDomain : APP_DOMAIN, TokenScopesArray : [ 'openid' , 'email' ], RedirectUriSignIn : REDIRECT_URI, RedirectUriSignOut : REDIRECT_URI_SIGNOUT, UserPoolId : USERPOOL_ID, } var auth = new CognitoAuth(authData); auth.userhandler = { onSuccess: function(result) { console.log( "On Success result" , result); UserInfoStore.setLoggedIn( true ); UserInfoApi.getUserInfo().then(response => { IndexRouter.push( '/' ); }); }, onFailure: function(err) { UserInfoStore.setLoggedOut(); IndexRouter.go({ path: '/error' , query: { message: 'Login failed due to ' + err } }); } }; function getUserInfoStorageKey(){ var keyPrefix = 'CognitoIdentityServiceProvider.' + auth.getClientId(); var tokenUserName = auth.signInUserSession.getAccessToken().getUsername(); var userInfoKey = keyPrefix + '.' + tokenUserName + '.userInfo' ; return userInfoKey; } var storageHelper = new StorageHelper(); var storage = storageHelper.getStorage(); export default { auth: auth, login(){ auth.getSession(); }, logout(){ if (auth.isUserSignedIn()) { var userInfoKey = this .getUserInfoStorageKey(); auth.signOut(); storage.removeItem(userInfoKey); } }, getUserInfoStorageKey, } |
Получение информации о пользователе от Amazon Cognito
После аутентификации мы можем использовать токен доступа для получения информации о пользователе, вошедшем в систему. Для этого нам нужно будет выполнить GET-запрос к конечной точке: https://<app domain>/oauth2/userInfo
. Мы создали служебный метод getUserInfo()
в src/app/user-info.js
как показано ниже:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
import axios from 'axios' ; import auth from './auth' ; export default { getUserInfo(){ var jwtToken = auth.auth.getSignInUserSession().getAccessToken().jwtToken; var requestData = { headers: { 'Authorization' : 'Bearer ' + jwtToken } } return axios.get(USERINFO_URL, requestData).then(response => { return response.data; }); } } |
Этот API был использован в оболочке Cognito, написанной в разделе выше.
Создание компонентов Vue
Давайте создадим несколько компонентов Vue для:
- отображая вошедшую в систему информацию о пользователе
- показывает выход из системы
- компонент обработки ошибок
Мы будем использовать Vue Router для отображения URL-пути к компонентам Vue. Определения компонентов показаны ниже:
Home
компонент
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
<template> <div class = "row" > <div class = "col" > <h3>Welcome, </h3> <div class = "alert alert-info" > {{userInfo}} </div> <router-link to= "/logout" > Logout </router-link> </div> </div> </template> <script> import UserInfoStore from '../app/user-info-store' ; export default { name: 'Home' , data: function() { return { userInfo: UserInfoStore.state.cognitoInfo } } } </script> <style> </style> |
Компонент LogoutSuccess
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
<template> <div class = "row" > <div class = "col" > <h2>Logged Out successfully</h2> <router-link to= "/login" >Login</router-link> </div> </div> </template> <script> export default { mounted: function(){ } } </script> |
Компонент ошибки:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
<template> <div class = "alert alert-danger" > {{message}} </div> </template> <script> export default { data: function(){ return { message: "" } }, mounted(){ this .message = this .$route.query.message; } } </script> |
Настройка роутера
Как упоминалось в предыдущем разделе, мы будем использовать Vue Router для сопоставления URL-пути с компонентами Vue. Мы настроим конфигурацию маршрутизатора в router/index.js
как показано ниже:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
/* eslint-disable */ import Vue from 'vue' import Router from 'vue-router' import Home from '@/components/Home' import auth from '../app/auth' ; import LogoutSuccess from '@/components/LogoutSuccess' ; import UserInfoStore from '../app/user-info-store' ; import UserInfoApi from '../app/user-info-api' ; import ErrorComponent from '@/components/Error' ; Vue.use(Router) function requireAuth(to, from, next) { if (!auth.auth.isUserSignedIn()) { UserInfoStore.setLoggedIn( false ); next({ path: '/login' , query: { redirect: to.fullPath } }); } else { UserInfoApi.getUserInfo().then(response => { UserInfoStore.setLoggedIn( true ); UserInfoStore.setCognitoInfo(response); next(); }); } } export default new Router({ mode: 'history' , base: '/' , routes: [ { path: '/' , name: 'Home' , component: Home, beforeEnter: requireAuth }, { path: '/login' , beforeEnter(to, from, next){ auth.auth.getSession(); } }, { path: '/login/oauth2/code/cognito' , beforeEnter(to, from, next){ var currUrl = window.location.href; //console.log(currUrl); auth.auth.parseCognitoWebResponse(currUrl); //next(); } }, { path: '/logout' , component: LogoutSuccess, beforeEnter(to, from, next){ auth.logout(); next(); } }, { path: '/error' , component: ErrorComponent } ] }) |
Мы используем свойство beforeEnter
объекта маршрутов для добавления любых предварительных beforeEnter
необходимых для визуализации компонента. И в этом свойстве мы проверяем, вошел ли пользователь в систему или не использует созданную нами оболочку Cognito. Таким образом, для путей, которые требуют защиты, мы можем определить свойство beforeEnter
.
Созданное приложение по умолчанию имеет компонент App.vue
который будет нашим корневым компонентом. Мы используем <router-view/>
чтобы указать, что HTML здесь будет основан на компоненте, к которому разрешается путь в конфигурации маршрутизатора.
Итак, наша версия App.vue
выглядит так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<template> <div id= "app" > <img alt= "Vue logo" src= "./assets/logo.png" > <div class = "contents" > <router-view/> </div> </div> </template> <script> export default { name: 'app' } </script> <style> #app { font-family: 'Avenir' , Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style> |
Затем мы обновляем src/main.js
для ссылки на каталог, который содержит конфигурацию маршрутизатора, как показано ниже:
01
02
03
04
05
06
07
08
09
10
|
import Vue from 'vue' import App from './App.vue' import router from './router' Vue.config.productionTip = false new Vue({ render: h => h(App), router }).$mount( '#app' ) |
Запуск приложения
Вы можете запустить приложение, введя команду: npm run serve
. Переход на localhost: 8080 приведет вас к экрану входа в Cognito:
Введите имя пользователя и пароль пользователя, которого вы зарегистрировали в пуле пользователей, или вы даже можете зарегистрироваться для нового пользователя. После входа вы будете перенаправлены обратно в приложение Vue JS:
Ссылка «Выход» приведет к выходу пользователя из системы.
Полный код можно найти в репозитории Github здесь .
Опубликовано на Java Code Geeks с разрешения Мохамеда Санауллы, партнера нашей программы JCG . См. Оригинальную статью здесь: Интеграция Amazon Cognito с одностраничным приложением (Vue.js) Мнения, высказанные участниками Java Code Geeks, являются их собственными. |