Нужна помощь с OAuth 2.0 на PHP.
Тип authorization code grant.
Мне нужно связать так называемый "навык" яндекс.алисы с моим сервером.
Я немного программирую, но в этом я первый раз и не всё понятно.
Вот тут Яндекс описывает протокол общения:
https://yandex.ru/dev/dialogs/alice/doc/auth/about...
Вот тут можно создать свой навык и попробовать:
https://dialogs.yandex.ru/developer
Я у себя всё подготовил. Свой VPS/VDS на debian 10, https, php.
Яндекс обращается к моему серверу и я должен произвести авторизацию и выдать токен.
Сделал auth.php:
<?
require_once('../bag_config_mysql.php');
$OpenHabAlice = new OpenHabAlice;
$user = $OpenHabAlice->user;
$password = $OpenHabAlice->password;
$db = $OpenHabAlice->db;
$dbhost = 'localhost';
$dbname = $db;
$dbusername = $user;
$dbpassword = $password;
$link = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbusername, $dbpassword);
$state = @$_GET['state'];
$redirect_uri = @$_GET['redirect_uri'];
$response_type = @$_GET['response_type'];
$client_id = @$_GET['client_id']; // Идентификатор приложения, который мы указывали при настройках навыка https://dialogs.yandex.ru/developer/skills/6408b0e1-4aa3-47bd-a41c-d5d3eb49bc21/draft/settings/main
$scope = @$_GET['scope'];
if (!isset($_POST['email']) and !isset($_POST['password'])){
if (isset($_GET['state']) and isset($_GET['redirect_uri']) and isset($_GET['response_type']) and isset($_GET['client_id']) and isset($_GET['scope'])){
$sth = $link->prepare("SELECT * FROM Alice WHERE client_id = :client_id");
$sth->execute(array('client_id' => $client_id));
$array = $sth->fetch(PDO::FETCH_ASSOC);
if (!$array){
$statement = $link->prepare('INSERT INTO Alice (state, redirect_uri, response_type, client_id, scope)
VALUES (:fstate, :fredirect_uri, :fresponse_type, :fclient_id, :fscope)');
$statement->execute([
'fstate' => $state,
'fredirect_uri' => $redirect_uri,
'fresponse_type' => $response_type,
'fclient_id' => $client_id,
'fscope' => $scope,
]);
$q_state = $statement->errorInfo();
$count = $statement->rowCount();
if ($count != 0){
echo "Мы внесли запись в БД";
} else {
echo "Не получилось внести в БД данные.";
print_r($q_state);
}
}
}
}
?>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
</head>
<body>
<?
if (isset($_POST['email']) and isset($_POST['password'])){
$username=$_POST['email'];
$password=$_POST['password'];
$URL='https://myopenhab.org/rest/';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$URL);
curl_setopt($ch, CURLOPT_TIMEOUT, 2);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($ch, CURLOPT_USERPWD, "$username:$password");
$result=curl_exec ($ch);
$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close ($ch);
if ($result == "Unauthorized"){
?>
<div class="div_for_alert2 regdiv d-flex justify-content-center">
<div class="alert alert-warning" role="alert">
Логин и пароль для myopenhab.ru не подошли
</div>
</div>
<?
$OpenHabTest = false;
} else {
$json = json_decode($result);
if (isset($json->runtimeInfo)){
$OpenHabTest = true;
$code = md5($client_id . $_POST['email'] . $_POST['password'] . rand());
$sth = $link->prepare("SELECT * FROM Alice WHERE client_id = :client_id");
$sth->execute(array('client_id' => $client_id));
$array = $sth->fetch(PDO::FETCH_ASSOC);
if (!$array){
print("Ошибка123.\n");
} else {
$sth = $link->prepare("UPDATE Alice SET oh_login = :flogin, oh_pass = :fpass, code = :code WHERE client_id = :fclient_id");
$sth->execute(array('fclient_id' => $client_id, 'flogin' => $_POST['email'], 'fpass' => $_POST['password'], 'code' => $code ));
$count = $sth->rowCount();
$q_state = $sth->errorInfo();
if ($count == 0){
print("Затронуто: $count строк.\n");
} else {
print("Затронуто: $count строк.\n");
}
}
$url = "$redirect_uri?code=$code&state=$state&client_id=$client_id&scope=$scope";
header("Location: $url");
} else {
$OpenHabTest = false;
}
}
} else {
}
?>
<div class="div_for_alert regdiv d-flex justify-content-center">
<div class="alert alert-secondary" role="alert">
Введите учётные данные с myopenhab.org
</div>
</div>
<div class="regdiv2 d-flex justify-content-center">
<form method="post">
<div class="form-group">
<label for="exampleInputEmail1">Email address</label>
<input type="email" name="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email">
</div>
<div class="form-group">
<label for="exampleInputPassword1">Password</label>
<input type="password" name="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
</div>
<button type="submit" class="btn btn-primary">Войти</button>
</form>
</div>
<style type="text/css">
.regdiv{
margin-top: 100px;
}
</style>
</body>
Яндекс на него присылает мне данные и я в auth.php формирую авторизацию/залогинивание.
И возвращаю яндексу на указанный redirect_uri соответствующие данные:
1. code = md5($client_id . $_POST['email'] . $_POST['password'] . rand());
2. state, client_id, scope - такие же, как и мне яндекс прислал
И яндекс успешно проглатывает эти данные и этот шаг считаю пройденным.
На шаге №2 Яндекс шлёт мне в token.php code, который я же ему сформировал на предыдущем шаге.
А ещё кроме code:
1. client_secret - это строка, которую я указал в настройках навыка.
2. grant_type = "authorization_code"
3. client_id - всё тотже id навыка
4. redirect_uri
И вот на этом шаге я не знаю что нужно сделать.
Пробовал посылать на redirect_uri GET данные:
1. access_token - рэндомно сгенерированный код и записанный в БД.
2. token_type='bearer', expires_in=86400, refresh_token=$8xLOxBtZp8
3. code, client_id, client_secret, grant_type - тоже самое, что прислал яндекс сюда в token.php
Файл token.php:
<html>
<head>
<meta charset="utf-8">
<title>Приём данных с алисы</title>
</head>
<body>
<?
if (isset($_REQUEST['code']) and isset($_REQUEST['client_secret']) and isset($_REQUEST['grant_type']) and isset($_REQUEST['client_id']) and isset($_REQUEST['redirect_uri'])){
$code = $_REQUEST['code'];
$client_secret = $_REQUEST['client_secret'];
$grant_type = $_REQUEST['grant_type'];
$client_id = $_REQUEST['client_id'];
$redirect_uri = $_REQUEST['redirect_uri'];
require_once('../bag_config_mysql.php');
$OpenHabAlice = new OpenHabAlice;
$user = $OpenHabAlice->user;
$password = $OpenHabAlice->password;
$db = $OpenHabAlice->db;
$dbhost = 'localhost';
$dbname = $db;
$dbusername = $user;
$dbpassword = $password;
$link = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbusername, $dbpassword);
$sth = $link->prepare("SELECT * FROM Alice WHERE client_id = :client_id AND code = :code");
$sth->execute(array('client_id' => $client_id, 'code' => $code));
$array = $sth->fetch(PDO::FETCH_ASSOC);
if (!$array){
echo "Ошибка! Нет такой связки client_id и code!";
} else {
$token = md5($client_id . $code . rand());
$sth = $link->prepare("UPDATE Alice SET token = :token WHERE client_id = :client_id AND code = :code");
$sth->execute(array('token' => $token, 'client_id' => $client_id, 'code' => $code ));
$count = $sth->rowCount();
$q_state = $sth->errorInfo();
if ($q_state[2] <> ""){
echo "Ошибка при обновлении записи в БД:";
print_r($q_state);
}
if ($count == 0){
print("Обновлено $count строк.\n");
} else {
$res_array = array('access_token' => $token, 'token_type' => 'bearer', 'expires_in' => 86400, 'refresh_token' => '8xLOxBtZp8');
echo json_encode($res_array);
$url = "$redirect_uri?access_token=$token&token_type='bearer'&expires_in=86400&refresh_token=$8xLOxBtZp8&code=$code&client_id=$client_id&client_secret=$client_secret&grant_type=$grant_type";
header("Location: $url");
}
}
}
?>
</body>
</html>
В результате Яндекс показывает на страничке "Произошла ошибка в процессе получения данных от сервиса":
Настройки яндекс навыка: