Прежде чем я начну, я хочу прояснить, что нижеследующее является доказательством концепции. Это абсолютно не рекомендация, а скорее отправная точка для разговора. В последнее время я много думал о том, как можно использовать OpenWhisk вместе с какой-то моделью безопасности. В частности, «Разоблачить действие такое-то и такое-то, но только для авторизованных пользователей». Очевидно, что «безопасность» может означать гораздо больше, но в этом начальном посте я собираюсь немного упростить свои требования.
- Аутентифицируйте пользователя как-нибудь.
- Сделать действие OpenWhisk Foo обязательным пользователем, вошедшим в систему.
Для аутентификации я прожевал несколько разных вещей. Теоретически я мог настроить базу данных Cloudant и создать действия для типичной процедуры регистрации/входа пользователя, но мне очень-очень не хотелось этого делать. Вместо этого я решил, наконец, взглянуть на Auth0. Я слышал об этом сервисе раньше, но никогда не видел возможности поиграть с ним. Оказалось, это было довольно легко. (У меня есть еще несколько комментариев по поводу Auth0, но я оставлю их в конце поста.) Я настроил новое приложение Auth0, используя их настройку Lock на стороне клиента для обработки аутентификации. Я создал невероятно плохую демо-версию на стороне клиента без реального пользовательского интерфейса и — да — я сказал, что это было плохо? Передняя часть состоит из двух кнопок:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width">
</head>
<body>
<p>
<button id="loginBtn">Login</button>
</p>
<p>
<button id="testFooBtn">Test Foo</button>
</p>
<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
<script src="https://cdn.auth0.com/js/lock/10.14/lock.min.js"></script>
<script src="app.js"></script>
</body>
</html>
Я включаю код Auth0 внизу вместе с jQuery. Мои две кнопки управляют входом в систему, а также вызовом действия, которое я продемонстрирую через минуту. Код JavaScript в основном взят из кода Auth0. Опять же, я хочу прояснить, что это всего лишь примерный код, позволяющий мне попробовать.
let lock;
let idToken;
$(document).ready( () => {
console.log('lets do this');
lock = new Auth0Lock('asKI36rzsbOyY40DaGv6mPWODbexIO-R','raymondcamden.auth0.com');
$('#loginBtn').on('click',doLogin);
$('#testFooBtn').on('click',doTestFoo);
idToken = localStorage.getItem('id_token');
if(idToken) {
getProfile();
}
lock.on("authenticated", function(authResult) {
console.dir(authResult);
localStorage.setItem('id_token', authResult.idToken);
idToken = authResult.idToken;
getProfile();
});
});
function doLogin() {
lock.show();
}
function getProfile() {
lock.getProfile(idToken, function(error, profile) {
if (error) {
// Handle error
return;
}
// Display user information
//show_profile_info(profile);
console.dir(profile);
});
}
Когда нажимается кнопка входа, я запускаю метод show Lock API. Вот где Auth0 действительно хорош. Он полностью обрабатывает процесс аутентификации и, в конце концов, оставляет мне JWT (веб-токен JSON), который я могу использовать для аутентификации моих последующих вызовов. Вызов getProfile взят из примера кода Auth0. Я на самом деле не использую его для чего-то практического. Позвольте мне показать вам, как это все выглядит.
Во-первых, страница, которая загружается по умолчанию (и опять же, это не должно быть готовым к работе):

А вот как выглядит процедура аутентификации Auth0:

Между прочим, Facebook и Google были выбраны произвольно — вы можете настроить это (опять же, я расскажу больше об Auth0 в конце).
После входа в систему я возвращаюсь на свою веб-страницу и имею доступ к моему профилю, но важным моментом является значение id_token. Это представляет значение JWT. Я могу использовать это в своем действии OpenWhisk для аутентификации запроса.
Проверка JWT довольно проста. Вот действие, которое я построил:
/*
hard coded secret
*/
const secret = require('./creds.json');
const jwt = require('jsonwebtoken');
/*
args.token, passed in
*/
function main(args) {
return new Promise( (resolve, reject) => {
let decoded = jwt.verify(args.token, secret.key, (err,decoded) => {
if(err) {
console.log('err',err);
reject({
name:err.name,
message:err.message,
stack:err.stack
});
} else {
resolve({decoded:decoded});
}
});
});
}
exports.main = main;
Для действия требуется два значения: ключ, специфичный для моего приложения и загружаемый через файл JSON, и сам JWT, который передается. Мне нужен пакет jsonwebtoken, в котором есть метод verify, который я могу запустить для проверки токен действителен как для моего приложения (в зависимости от значения секрета), так и в течение определенного периода времени. И это все. Серьезно - красиво и просто, правда? Я назвал это действие jwtverify.
Итак, чтобы свести это воедино, мне нужно создать действие, которое будет обеспечено. Я создаю следующее очень простое действие с именем foo.
function main(args) {
if(!args.name) args.name = 'Nameless';
return {
result:"Hello "+args.name
}
}
Я подтолкнул это к OpenWhisk. Теперь у меня есть общее действие «jwt verify» и случайное действие, которое я хочу защитить. Как мне это сделать? С последовательностью. Я создал новое действие под названием secureFoo, основанное на последовательности: jwtverify+foo. (Технически я сделал все это в пакете под названием secblog просто для того, чтобы немного организовать демонстрацию.) Конечным результатом является действие, которое действует как приложение Express с промежуточным программным обеспечением.
Для тестирования я выставил secureFoo через REST API (не как веб-экшен, потому что CORS пока не является простым дополнением). Затем я создал эту функцию для поддержки этой второй кнопки в моем демонстрационном приложении:
function doTestFoo() {
$.get('https://3b1fd5b1-e8cc-4871-a7d8-cc599e3ef852-gws.api-gw.mybluemix.net/auth1/foo?token='+idToken+'&name=Ray').then((res) => {
console.log(res);
});
}
URL-адрес, который вы видите, — это путь, который я указал для своего REST API. Решающий бит находится в конце, где я передаю токен. Это передается первому действию в последовательности, которое проверяет его, а затем переходит ко второму. В результате вы ожидаете:

Вау! Хорошо, готово… вроде. Вы заметили, что мое действие Foo приняло аргумент? Я передал name=Ray в URL, но это не отразилось на результате. Одна важная вещь, которую следует помнить о последовательностях, заключается в том, что аргументы, отправленные в качестве входных данных, относятся только к первому действию. Если вы хотите, чтобы любое последующее действие работало с вводом, оно должно быть передано как результат каждого предыдущего действия.
Поскольку наше первое действие — это обычная вещь типа «защитить этот процесс», один подход, который мы могли бы использовать, — это просто передать все, что было отправлено, кроме исходного токена. Я изменил свой проверочный код следующим образом:
delete args.token;
resolve(args);
И просто так — это работает. Я не буду делать новый снимок экрана, так как он буквально только что изменился с Nameless на Ray. Одна проблема с этой конкретной настройкой заключается в том, что «токен» теперь, по сути, является зарезервированным словом. Поскольку это мое приложение, и я создаю API, я могу с этим справиться.
Итак… вот и все. Как я уже сказал, я определенно не уверен, насколько это имеет смысл, но я хотел бы услышать мнение людей. Оставьте мне комментарий ниже! Вы можете найти исходный код всего, что я показал здесь: https://github.com/cfjedimaster/Serverless-Examples/tree/master/auth1
Остановить чтение
Или нет. ;) Как я уже сказал выше, Auth0 чертовски хорош. Все в них меня просто впечатлило. Зарегистрироваться было легко. У них была дерьмовая тонна образцов, я имею в виду, черт возьми, почти ошеломляющих с точки зрения примера кода. Одна вещь, которая мне особенно чертовски понравилась, это то, что вы можете протестировать вход через социальные сети, и они будут использовать свои собственные приложения, пока вы не укажете свое собственное. Я имею в виду, что обычно для входа через социальные сети вы заходите на сайт, создаете новое приложение, записываете различные идентификаторы, возвращаетесь к своему коду, копируете их и т. д. и т. д. Это, конечно, не сложно, но скучно. . С Auth0, конечно, только при тестировании, вы можете просто использовать их приложения. Я действительно копаю это! В любом случае, я надеюсь еще много поиграть с Auth0 в будущем, и пока что я определенно могу его рекомендовать!
Первоначально опубликовано на сайте www.raymondcamden.com 17 апреля 2017 г.