Я также обнаружил, что документация может быть немного запутанной. Но после многих часов попыток я понял это с помощью this blog (обновление - блог больше не существует, изменен на Интернет-архив). В вашем случае вам не нужна запись брандмауэра для ^/oauth/v2/auth
, потому что это для страницы авторизации. Вы должны помнить, что oAuth может сделать ... он используется не только для REST api. Но если REST api - это то, что вы хотите защитить, вам это не нужно.вот пример конфигурации брандмауэра из моего приложения:
firewalls:
oauth_token:
pattern: ^/oauth/v2/token
security: false
api_firewall:
pattern: ^/api/.*
fos_oauth: true
stateless: true
anonymous: false
secure_area:
pattern: ^/
fos_oauth: true
form_login:
provider: user_provider
check_path: /oauth/v2/auth_login_check
login_path: /oauth/v2/auth_login
logout:
path: /logout
target:/
anonymous: ~
access_control:
- { path: ^/oauth/v2/auth_login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/, roles: IS_AUTHENTICATED_FULLY }
Обратите внимание, что вам необходимо определить поставщика услуг. Если вы используете FOSUserBundle, для вас уже создан пользовательский провайдер. В моем случае я сделал свой собственный и создал сервис из него.
И в моем config.yml:
fos_oauth_server:
db_driver: orm
client_class: BB\AuthBundle\Entity\Client
access_token_class: BB\AuthBundle\Entity\AccessToken
refresh_token_class: BB\AuthBundle\Entity\RefreshToken
auth_code_class: BB\AuthBundle\Entity\AuthCode
service:
user_provider: platform.user.provider
options:
supported_scopes: user
Следует также отметить, что таблицы, создаваемые в базе данных (access_token, клиент, AUTH_CODE, refresh_token) должны иметь больше полей, чем то, что показано в документации ...
токен доступа Таблица: идентификатор (целое), client_id (целое), user_id (INT), маркер (строка), область (строка), expires_at (интермедиат)
Таблица клиентов: идентификатор (целое), random_id (строка), секрет (строка), redirect_urls (строка), allowed_grant_types (строка)
Auth Таблица кодов: идентификатор (целое), client_id (целое), user_id (целое)
Refresh токен Таблица: идентификатор (целое), client_id (целое), user_id (INT), маркер (строка), expires_at (INT), область (строка)
Эти таблицы будут хранить информацию, необходимую для oAuth, так что обновите свои объекты Doctrine, чтобы они соответствовали таблицам db, как указано выше.
И тогда вам нужен способ, чтобы фактически генерировать секрет и client_id, так что это, где «Создание клиента» раздел из документации приходит, хотя это не очень полезно ...
Создать файл на /src/My/AuthBundle/Command/CreateClientCommand.php
(вам нужно будет создать папку Command
) Этот код из статьи я связан выше, и показывает пример того, что вы можете поместить в этот файл:
<?php
# src/Acme/DemoBundle/Command/CreateClientCommand.php
namespace Acme\DemoBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class CreateClientCommand extends ContainerAwareCommand
{
protected function configure()
{
$this
->setName('acme:oauth-server:client:create')
->setDescription('Creates a new client')
->addOption(
'redirect-uri',
null,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'Sets redirect uri for client. Use this option multiple times to set multiple redirect URIs.',
null
)
->addOption(
'grant-type',
null,
InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY,
'Sets allowed grant type for client. Use this option multiple times to set multiple grant types..',
null
)
->setHelp(
<<<EOT
The <info>%command.name%</info>command creates a new client.
<info>php %command.full_name% [--redirect-uri=...] [--grant-type=...] name</info>
EOT
);
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$clientManager = $this->getContainer()->get('fos_oauth_server.client_manager.default');
$client = $clientManager->createClient();
$client->setRedirectUris($input->getOption('redirect-uri'));
$client->setAllowedGrantTypes($input->getOption('grant-type'));
$clientManager->updateClient($client);
$output->writeln(
sprintf(
'Added a new client with public id <info>%s</info>, secret <info>%s</info>',
$client->getPublicId(),
$client->getSecret()
)
);
}
}
Тогда на самом деле создать client_id и секрет, выполните эту команду из командной строки (это введет в базу данных необходимые идентификаторы и материал):
php app/console acme:oauth-server:client:create --redirect-uri="http://clinet.local/" --grant-type="password" --grant-type="refresh_token" --grant-type="client_credentials"
уведомление о том, что acme:oauth-server:client:create
может быть все, что вы на самом деле назвать свою команду в CreateClientCommand.php
файл с $this->setName('acme:oauth-server:client:create')
.
Как только у вас есть client_id и секрет, вы готовы к аутентификации. Сделайте запрос в браузере, который что-то вроде этого:
http://example.com/oauth/v2/token?client_id=[CLIENT_ID_YOU GENERATED]&client_secret=[SECRET_YOU_GENERATED]&grant_type=password&username=[USERNAME]&password=[PASSWORD]
Надеемся, что она работает на вас. Определенно нужно настраивать, просто постарайтесь сделать это шаг за шагом.
Я также написал простой PHP-класс для вызова моего Symfony REST api, используя oAuth, если вы считаете, что это было бы полезно, сообщите мне, и я могу его передать.
UPDATE
В ответ на Ваши дополнительные вопросы:
«Клиент» описывается на одном блоге, только в другой статье. Прочтите раздел Clients and Scopes здесь, он должен уточнить для вас, что такое клиент. Как упоминалось в статье, для каждого пользователя вам не нужен клиент. Если хотите, у вас может быть один клиент для всех ваших пользователей.
Я также использую классическую аутентификацию Symfony для моего сайта, но это может измениться в будущем. Поэтому всегда хорошо держать эти вещи в глубине вашего разума, но я бы не сказал, что странно сочетать эти два метода.
Refresh_token используется, когда срок действия access_token истек, и вы хотите запросить новый access_token без повторной отправки учетных данных пользователя. вместо этого вы отправляете токен обновления и получаете новый access_token. Это не обязательно для REST API, потому что один запрос, вероятно, не займет достаточно много времени для истечения срока действия access_token.
oAuth1 и oAuth2 очень разные, поэтому я бы предположил, что метод, который вы используете, не будет работать, но я никогда не пробовал с этим. Но только для тестирования вы можете сделать обычный запрос GET или POST, если вы передаете access_token=[ACCESS_TOKEN]
в строке запроса GET (фактически для всех типов запросов).
Но в любом случае, вот мой класс. Я использовал файл конфигурации для хранения некоторых переменных, и я не реализовал возможность DELETE, но это не так сложно.
class RestRequest{
private $token_url;
private $access_token;
private $refresh_token;
private $client_id;
private $client_secret;
public function __construct(){
include 'config.php';
$this->client_id = $conf['client_id'];
$this->client_secret = $conf['client_secret'];
$this->token_url = $conf['token_url'];
$params = array(
'client_id'=>$this->client_id,
'client_secret'=>$this->client_secret,
'username'=>$conf['rest_user'],
'password'=>$conf['rest_pass'],
'grant_type'=>'password'
);
$result = $this->call($this->token_url, 'GET', $params);
$this->access_token = $result->access_token;
$this->refresh_token = $result->refresh_token;
}
public function getToken(){
return $this->access_token;
}
public function refreshToken(){
$params = array(
'client_id'=>$this->client_id,
'client_secret'=>$this->client_secret,
'refresh_token'=>$this->refresh_token,
'grant_type'=>'refresh_token'
);
$result = $this->call($this->token_url, "GET", $params);
$this->access_token = $result->access_token;
$this->refresh_token = $result->refresh_token;
return $this->access_token;
}
public function call($url, $method, $getParams = array(), $postParams = array()){
ob_start();
$curl_request = curl_init();
curl_setopt($curl_request, CURLOPT_HEADER, 0); // don't include the header info in the output
curl_setopt($curl_request, CURLOPT_RETURNTRANSFER, 1); // don't display the output on the screen
$url = $url."?".http_build_query($getParams);
switch(strtoupper($method)){
case "POST": // Set the request options for POST requests (create)
curl_setopt($curl_request, CURLOPT_URL, $url); // request URL
curl_setopt($curl_request, CURLOPT_POST, 1); // set request type to POST
curl_setopt($curl_request, CURLOPT_POSTFIELDS, http_build_query($postParams)); // set request params
break;
case "GET": // Set the request options for GET requests (read)
curl_setopt($curl_request, CURLOPT_URL, $url); // request URL and params
break;
case "PUT": // Set the request options for PUT requests (update)
curl_setopt($curl_request, CURLOPT_URL, $url); // request URL
curl_setopt($curl_request, CURLOPT_CUSTOMREQUEST, "PUT"); // set request type
curl_setopt($curl_request, CURLOPT_POSTFIELDS, http_build_query($postParams)); // set request params
break;
case "DELETE":
break;
default:
curl_setopt($curl_request, CURLOPT_URL, $url);
break;
}
$result = curl_exec($curl_request); // execute the request
if($result === false){
$result = curl_error($curl_request);
}
curl_close($curl_request);
ob_end_flush();
return json_decode($result);
}
}
И затем использовать класс, просто:
$request = new RestRequest();
$insertUrl = "http://example.com/api/users";
$postParams = array(
"username"=>"test",
"is_active"=>'false',
"other"=>"3g12g53g5gg4g246542g542g4"
);
$getParams = array("access_token"=>$request->getToken());
$response = $request->call($insertUrl, "POST", $getParams, $postParams);
Спасибо очень очень Munch @Sehael, это действительно полезно! У меня есть мой клиент, и я могу генерировать токены пользователем. Однако я отредактировал этот вопрос, потому что у меня все еще есть последние (надеюсь) взаимодействия. – maphe
Я обновил свой ответ с дальнейшим объяснением – Sehael
Большое спасибо! Вы спасли меня;) – maphe