我也發現文檔可能有點混亂。但經過數小時的嘗試,我在this blog(更新 - 博客不再存在,更改爲Internet Archive)的幫助下計算出來了。在你的情況下,你不需要^/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)都要求有比所顯示的更多的字段在文檔...
訪問令牌表: ID(INT),CLIENT_ID(INT),USER_ID(INT),令牌(串),範圍(串),expires_at(INT)
客戶端表: ID(INT),random_id(串),祕密(串),redirect_urls(串),allowed_grant_types(串)
授權碼錶: ID(INT),CLIENT_ID(INT),USER_ID(INT)
刷新令牌表: ID(INT),CLIENT_ID(INT),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和祕密,從命令行執行這個命令(這將插入到數據庫中必要的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和secret,你就可以進行身份驗證了。使你的瀏覽器的請求是這樣的:
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類來使用oAuth調用我的Symfony REST api,如果你認爲那會很有用,讓我知道,我可以傳遞它。
UPDATE
在回答您的其他問題:
的「客戶端」在同一個博客,只是不同的文章中描述。在這裏閱讀Clients and Scopes部分,它應該爲您澄清客戶是什麼。就像文章中提到的,你不需要每個用戶的客戶端。如果您願意,您可以爲所有用戶提供單一客戶端。
我其實也在爲我的前端網站使用經典的Symfony驗證,但這在將來可能會改變。所以把這些東西放在頭腦裏總是好的,但我不會說把這兩種方法結合起來是很奇怪的。
refresh_token在access_token過期並且您希望請求新的access_token而不重新發送用戶憑證時使用。相反,您發送刷新令牌並獲得一個新的access_token。這對於REST API來說並不是必需的,因爲一個請求可能不會花費足夠長的時間來使access_token過期。
oAuth1和oAuth2是非常不同的,所以我會假設你使用的方法不起作用,但我從來沒有嘗試過。但只是爲了測試,只要您在GET查詢字符串中(實際上針對所有類型的請求)傳遞access_token=[ACCESS_TOKEN]
,就可以進行正常的GET或POST請求。
但無論如何,這裏是我的課程。我用一個配置文件來存儲一些變量,而且我沒有實現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);
謝謝你非常非常蒙克@Sehael,這是非常有幫助!我有我的客戶,我可以由用戶生成令牌。不過,我編輯了這個問題,因爲我仍然有最後一個(我希望)interogations。 – maphe
我更新了我的答案並提供了進一步的解釋 – Sehael
非常感謝!你救了我;) – maphe