Я разработал несколько веб-API на PHP, используя Slim Framework, который используется мобильными приложениями (iOS и Android) для обработки их запросов и получения необходимых данных.
В конце концов, в каждом API я отправляю запросы, полученные из мобильного приложения, соответствующей функции, присутствующей в кодовой базе моего сайта. Затем соответствующая функция принимает запрос и параметры запроса, обрабатывает запрос и возвращает необходимые данные. Затем API возвращает данные в мобильное приложение в формате JSON. Это текущий рабочий процесс.
Теперь я хочу сделать доступность ресурсов сайта (т.е. функций из базы кода и данных сайта) подлежащей аутентификации пользователя. Короче говоря, я хочу реализовать схему «Аутентификация на основе токенов» в этом сценарии.
После реализации «Аутентификации на основе токенов» должен быть следующий процесс:
Когда пользователь впервые входит в систему, отправляя имя пользователя и пароль в запросе API входа в систему, один токен безопасности будет генерироваться после успешной проверки комбинации имени пользователя и пароля для этого конкретного пользователя. Этот токен безопасности также будет сохранен в некоторой таблице базы данных MySQL вместе с именем пользователя / паролем / некоторым хешированным значением для идентификации пользователя в дальнейшей обработке. Если проверка не пройдена, маркер безопасности не должен генерироваться, и пользователь также не должен входить в систему.
При успешном входе в систему сгенерированный токен безопасности будет отправлен обратно пользователю при успешном ответе API входа в систему. Теперь, пока пользователь не войдет в систему с каждым последующим запросом, этот токен будет отправлен соответствующему API и, в конечном счете, он будет отправлен в функцию аутентификации для аутентификации его действительности.
Если по какому-либо запросу был отправлен недействительный токен, то в ответ должно быть отправлено сообщение «Пожалуйста, войдите в систему», и ресурс сайта не должен получить доступ.
После того как пользователь выйдет из системы, эту запись маркера безопасности следует удалить из базы данных или предпринять соответствующие действия.
С тех пор, как я работаю над «Аутентификацией на основе токенов» впервые в своей карьере, я могу ошибаться в своем вышеописанном подходе. Если я делаю что-то не так, исправьте мои ошибки.
Я нашел следующие ссылки, но те, которые я не нашел много полезного, так как им не хватает примера рабочего кода с пошаговым описанием:
PHP HMAC Restful API, который использует платформу Phalcon Micro
Если бы вы могли предоставить мне весь код, который состоит из создания таблицы базы данных, соединения между PHP и MySQL, затем создания токена безопасности, проверки действительности токена безопасности для текущего вошедшего в систему пользователя и т. Д., Это было бы действительно здорово для меня.
Кроме того, если бы вы могли привести пример рабочего кода для любого из двух вышеупомянутых (или обоих) вариантов в качестве ответа на этот вопрос, это также было бы очень здорово. Если у вас есть другие варианты, кроме двух, которые я предоставил с полным примером рабочего кода, добро пожаловать в ваш ответ.
N.B. :- Пожалуйста, не предлагайте мне использовать процесс аутентификации OAuth.
Ниже приведен код, который я пробовал самостоятельно, но я не знаю, правильно он или нет. Мой подход правильный или неправильный?
Для создания токена я использую эту функцию, которая принимает в качестве параметров данные пользователя
define('SECRET_KEY', "fakesecretkey");
function createToken($data)
{
/* Create a part of token using secretKey and other stuff */
$tokenGeneric = SECRET_KEY.$_SERVER["SERVER_NAME"]; // It can be 'stronger' of course
/* Encoding token */
$token = hash('sha256', $tokenGeneric.$data);
return array('token' => $token, 'userData' => $data);
}
Таким образом, пользователь может аутентифицировать себя и получить массив, который содержит токен (genericPart + его данные, закодированные) и его данные не закодированы:
function auth($login, $password)
{
// we check user. For instance, it's ok, and we get his ID and his role.
$userID = 1;
$userRole = "admin";
// Concatenating data with TIME
$data = time()."_".$userID."-".$userRole;
$token = createToken($data);
echo json_encode($token);
}
Затем пользователь может отправить мне свой токен + свои некодированные данные, чтобы проверить:
define('VALIDITY_TIME', 3600);
function checkToken($receivedToken, $receivedData)
{
/* Recreate the generic part of token using secretKey and other stuff */
$tokenGeneric = SECRET_KEY.$_SERVER["SERVER_NAME"];
// We create a token which should match
$token = hash('sha256', $tokenGeneric.$receivedData);
// We check if token is ok !
if ($receivedToken != $token)
{
echo 'wrong Token !';
return false;
}
list($tokenDate, $userData) = explode("_", $receivedData);
// here we compare tokenDate with current time using VALIDITY_TIME to check if the token is expired
// if token expired we return false
// otherwise it's ok and we return a new token
return createToken(time()."#".$userData);
}
$check = checkToken($_GET['token'], $_GET['data']);
if ($check !== false)
echo json_encode(array("secureData" => "Oo")); // And we add the new token for the next request
Я прав?
Основываясь на нашем обсуждении, вы можете сделать что-то похожее на OAuth2.0. Я бы порекомендовал реализовать полную спецификацию, но, поскольку это ваше приложение, вы можете внести изменения.
Вот график из RFC 6750
+--------+ +---------------+
| |--(A)- Authorization Request ->| Resource |
| | | Owner |
| |<-(B)-- Authorization Grant ---| |
| | +---------------+
| |
| | +---------------+
| |--(C)-- Authorization Grant -->| Authorization |
| Client | | Server |
| |<-(D)----- Access Token -------| (Slim API) |
| | +---------------+
| |
| | +---------------+
| |--(E)----- Access Token ------>| Resource |
| | | Server |
| |<-(F)--- Protected Resource ---| |
+--------+ +---------------+
В Slim у вас может быть всего три конечных точки:
POST имя пользователя / пароль:
/ OAuth / v1 / Authenticate /
возвращается { token: foo }
GET где {токен} — ваш уникальный токен
/ OAuth / v1 / маркер / {маркер}
возвращается { username: joe, permissions['page:admin','users:full'], expires: 123456}
УДАЛИТЬ передать {токен}
/ OAuth / v1 / маркер / отменить
отвечает с 200 OK
и пустое тело.
Теперь, как это работает:
token
, который клиент хранит в виде файла cookie.GET / ресурс HTTP / 1.1
Host: server.example.com Authorization: Bearer mF_9.B5f-4.1JqM
Ваш ресурсный сервер связывается с Slim API на серверной части, чтобы определить ваши разрешения. Затем сервер решает, что вам разрешено видеть.
Если вам не нравится отправлять его в качестве заголовка, см. раздел 2.2, который описывает, как отправить его в теле, или раздел 2.3 который отправляет его как запрос URI.
Это, очевидно, не должны быть разные серверы. Вы можете реализовать это как хотите.
Вы могли бы сделать это таким образом.
У каждого пользователя есть закрытый ключ (случайный буквенно-цифровой Икс длинная строка) — которая уникальна для каждого пользователя.
На каждый запрос вы можете hash_hmac
запрос с их закрытым ключом, который сгенерирует уникальный ключ запроса для каждого пользователя. Например:
Request:
GET /v1/products/coffee
Private key:
ww9k6fcysu30sbuzu7ez57z2kzvefyxwosrjcnwo
Затем я бы сгенерировал ключ запроса как;
hash_hmac("sha1", "GET /v1/products/coffee", "ww9k6fcysu30sbuzu7ez57z2kzvefyxwosrjcnwo");
Это дало бы мне ключ запроса: 45751dce6ef93655a71e7b82a6179591c346c2c1
за это GET
только запрос Это также гарантирует, что клиент предназначен для этой конечной точки и не был подделан.
На приемном конце вы бы сделали то же самое hash_hmac
Подпрограмма с закрытым ключом пользователя (например, в запросе необходимо указать свое имя пользователя — например, чтобы выполнить поиск для извлечения закрытого ключа) и сравнить два результата.
hash_hmac("sha1", $_SERVER['REQUEST_METHOD'] . " " . $_SERVER['REDIRECT_URL'], $user_private_key);
Для дополнительного бонуса вы получите хеш для содержимого тела POST / PUT, добавите его в строку запроса и подтвердите его на принимающей стороне. Например;
$bodyhash = md5(implode(",", $_POST));
Когда пользователь выходит из системы, деактивируйте закрытый ключ и назначьте ему новый при следующем входе в систему.