Symfony Advent Calendar 2016 の 13日目の投稿です。FOSOAuthServerBundle の基本的な導入と利用について日本語でまとまっている記事がなかったので書いてみました。WEB API、ユーザーシステムの下地として、FOSRestBundle, FOSUserBunble も利用しています。
今回、実装したデモ用のソースコードは以下に置いて置いてあります
概要
- FOSOAuthServerBundle を利用してトークン認証が必要な WEB API のデモを作りました。
- FOSOAuthServerBundle による トークン発行、トークンのリフレッシュ、有効期限が切れたトークンの削除 の方法について説明しました。
1. 環境
- Symfony 2.8
- PHP 7.0.8
- MySQL
2. ユーザーシステムとデモ API を作成
では、さっそく取り掛かっていきます。
まず、Symfony Installer でプロジェクトを作成し、FOSRestBundle, FOSUserBundle を追加しユーザーシステムとデモ API をセットアップしていきます。手順の説明は、公式ドキュメントに記載がありますので今回は省略します。以下の公式ドキュメントを参考にしてください。
- Installing & Setting up the Symfony Framework
- Getting Started With FOSRestBundle
- Getting Started With FOSUserBundle
STEP 2.1 プロジェクトの作成
$ symfony new symfony-oauth-sever 2.8
$ cd symfony-oauth-server
STEP 2.2 Bundle のインストール
$ composer require friendsofsymfony/rest-bundle 1.3.*
$ composer require friendsofsymfony/user-bundle
$ composer require jms/serializer-bundle
...
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = array(
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
new Symfony\Bundle\MonologBundle\MonologBundle(),
new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
new AppBundle\AppBundle(),
// 追加
new FOS\RestBundle\FOSRestBundle(),
new FOS\UserBundle\FOSUserBundle(),
new JMS\SerializerBundle\JMSSerializerBundle(),
);
...
}
STEP 2.3 Bundle の設定
fos_rest:
routing_loader:
default_format: json
include_format: false
fos_user:
db_driver: orm
firewall_name: api
user_class: AppBundle\Entity\User
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
STEP 2.4 User Entity クラスの作成
<?php
// src/AppBundle/Entity/User.php
namespace AppBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
public function __construct()
{
parent::__construct();
// your own logic
}
}
STEP 2.5 データベースの準備
$ php app/console doctrine:database:create
$ php app/console doctrine:schema:update --force
mysql> use symfony-oauth-server;
mysql> show tables;
+--------------------------------+
| Tables_in_symfony-oauth-server |
+--------------------------------+
| fos_user |
+--------------------------------+
1 rows in set (0.00 sec)
STEP 2.6 ユーザの作成
$ php app/console fos:user:create
Please choose a username:admin
Please choose an email:admin@example.com
Please choose a password:adminpass
Created user admin
mysql> select * from fos_user;
+----+----------+--------------------+-------------------+-------------------+---------+---------------------------------+--------------------------------------------------------------+------------+--------+---------+------------+--------------------+-----------------------+--------+---------------------+-----------------------+
| id | username | username_canonical | email | email_canonical | enabled | salt | password | last_login | locked | expired | expires_at | confirmation_token | password_requested_at | roles | credentials_expired | credentials_expire_at |
+----+----------+--------------------+-------------------+-------------------+---------+---------------------------------+--------------------------------------------------------------+------------+--------+---------+------------+--------------------+-----------------------+--------+---------------------+-----------------------+
| 1 | admin | admin | admin@example.com | admin@example.com | 1 | kjflxygblxcwccgkg4o4ooggkckgggw | $2y$13$kjflxygblxcwccgkg4o4oe34L7Y6Iorvaz4V5Sr9lg3nbSnHn.b.i | NULL | 0 | 0 | NULL | NULL | NULL | a:0:{} | 0 | NULL |
+----+----------+--------------------+-------------------+-------------------+---------+---------------------------------+--------------------------------------------------------------+------------+--------+---------+------------+--------------------+-----------------------+--------+---------------------+-----------------------+
1 row in set (0.01 sec)
STEP 2.7 API の作成
api:
resource: "@AppBundle/Controller/"
prefix: api
type: rest
<?php
namespace AppBundle\Controller;
use FOS\RestBundle\Controller\Annotations\RouteResource;
use FOS\RestBundle\Controller\FOSRestController;
/**
* @RouteResource("welcome")
*/
class WelcomeController extends FOSRestController
{
public function getAction()
{
return ["welcome!"];
}
}
STEP 2.8 動作確認
PHP の build-in server で動作を確認します。
$ php app/console server:start
HTTP のリクエストには HTTPie を利用しています。ユーザーフレンドリーなシンタックスやハイライトを提供してくれて JSON にも対応しているためオススメです。
$ http GET http://localhost:8000/app_dev.php/api/welcome
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Type: application/json
[
"welcome!"
]
・・・はい、さくっとできましたね 新しいバンドル導入方法は、多くのバンドルで同じ流れが多いのでいまいちピンと来てない方は再度おさらいしておくことをオススメします
3. FOSOAuthServerBundle を導入する
では、ここからが本編です。FOSOAuthServerBundle を使っていきます。
まずはインストールから。
STEP 3.1 インストール
$ composer require friendsofsymfony/oauth-server-bundle
...
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = array(
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
new Symfony\Bundle\MonologBundle\MonologBundle(),
new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
new AppBundle\AppBundle(),
// 追加
new FOS\OAuthServerBundle\FOSOAuthServerBundle(),
new FOS\RestBundle\FOSRestBundle(),
new FOS\UserBundle\FOSUserBundle(),
new JMS\SerializerBundle\JMSSerializerBundle(),
);
...
}
STEP 3.2 Entity の追加
次に利用する Entity を追加していきます。追加する Entity は以下の4つです。
-
1) AccessToken.php
src/AppBundle/Entity/AccessToken.php<?php namespace AppBundle\Entity; use FOS\OAuthServerBundle\Entity\AccessToken as BaseAccessToken; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ class AccessToken extends BaseAccessToken { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @ORM\ManyToOne(targetEntity="Client") * @ORM\JoinColumn(nullable=false) */ protected $client; /** * @ORM\ManyToOne(targetEntity="AppBundle\Entity\User") */ protected $user; }
-
2) AuthCode.php
src/AppBundle/Entity/AuthCode.php<?php namespace AppBundle\Entity; use FOS\OAuthServerBundle\Entity\AuthCode as BaseAuthCode; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ class AuthCode extends BaseAuthCode { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @ORM\ManyToOne(targetEntity="Client") * @ORM\JoinColumn(nullable=false) */ protected $client; /** * @ORM\ManyToOne(targetEntity="AppBundle\Entity\User") */ protected $user; }
-
3) Client.php
src/AppBundle/Entity/Client.php<?php namespace AppBundle\Entity; use FOS\OAuthServerBundle\Entity\Client as BaseClient; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ class Client extends BaseClient { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; }
-
4) RefreshToken.php
src/AppBundle/Entity/RefreshToken.php<?php namespace AppBundle\Entity; use FOS\OAuthServerBundle\Entity\RefreshToken as BaseRefreshToken; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity */ class RefreshToken extends BaseRefreshToken { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @ORM\ManyToOne(targetEntity="Client") * @ORM\JoinColumn(nullable=false) */ protected $client; /** * @ORM\ManyToOne(targetEntity="AppBundle\Entity\User") */ protected $user; }
STEP 3.3 データベースの準備
$ php app/console doctrine:schema:update --force
+--------------------------------+
| Tables_in_symfony-oauth-server |
+--------------------------------+
| access_token |
| auth_code |
| client |
| fos_user |
| refresh_token |
+--------------------------------+
5 rows in set (0.00 sec)
STEP 3.4 設定の追加
config.yml に設定を追加していきます。
fos_oauth_server:
db_driver: orm # Drivers available: orm, mongodb, or propel
client_class: AppBundle\Entity\Client
access_token_class: AppBundle\Entity\AccessToken
refresh_token_class: AppBundle\Entity\RefreshToken
auth_code_class: AppBundle\Entity\AuthCode
service:
user_provider: fos_user.user_provider.username
ルーティングも追加します。
fos_oauth_server_token:
resource: "@FOSOAuthServerBundle/Resources/config/routing/token.xml"
fos_oauth_server_authorize:
resource: "@FOSOAuthServerBundle/Resources/config/routing/authorize.xml"
serurity.yml に認証の設定を追加しましょう。
# To get started with security, check out the documentation:
# http://symfony.com/doc/current/security.html
security:
encoders:
FOS\UserBundle\Model\UserInterface: bcrypt
# http://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded
providers:
in_memory:
memory: ~
firewalls:
oauth_token:
pattern: ^/oauth/v2/token
security: false
api:
pattern: ^/api
fos_oauth: true
stateless: true
anonymous: false # can be omitted as its default value
access_control:
- { path: ^/api, roles: [ IS_AUTHENTICATED_FULLY ] }
この設定で、全ての API はトークン認証なしにはアクセスできなります。ここまで進んだところで、先程作成した Welcom API を叩いてアクセスが拒否されることを確認してみましょう。
$ http GET http://localhost:8000/app_dev.php/api/welcome
HTTP/1.1 401 Unauthorized
Cache-Control: no-store, private
Content-Type: application/json
Host: localhost:8000
Pragma: no-cache
WWW-Authenticate: Bearer realm="Service", error="access_denied", error_description="OAuth2 authentication required"
{
"error": "access_denied",
"error_description": "OAuth2 authentication required"
}
無事にアクセスが拒否されています ここからは、この API にトークン認証でアクセスできるようにしていきます。
4. OAuth によるトークン認証
はい。ではここから FOSOAuthServerBundle で OAuth によるトークン認証を試していきます。今回試す Grant Type は Resource Owner Password Credentials とします。
STEP 4.1 クライアントの作成
まず、クライアントを作成します。ぐぐってみると、FOSOAuthServerBundle でクライアントを発行するにはいくつかみつかりました。
- SQL で登録
- WEB フォームから登録
- Symfony Command で登録
せっかくなので、Symfony Command で作ってみます
なお、FOSOAuthServerBundle が Symfony Command を用意しているわけではなく、自前で実装する必要があります。
<?php
namespace AppBundle\Command;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class CreateOAuthClientCommand extends ContainerAwareCommand
{
protected function configure()
{
$this
->setName('app:oauth-client:create')
->setDescription('Create OAuth Client.')
->addArgument('redirectUri', InputArgument::REQUIRED, 'The redirect uri')
->addArgument('grantType', InputArgument::REQUIRED, 'The grant type')
->setHelp(<<<EOT
The <info>app:oauth:create</info> command creates a OAuth Client:
<info>php app/console app:oauth:create</info>
This interactive shell will ask you for an client name, a redirect uri and then a grant type.
EOT
);
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$redirectUri = $input->getArgument('redirectUri');
$grantType = $input->getArgument('grantType');
$clientManager = $this->getContainer()->get('fos_oauth_server.client_manager.default');
$client = $clientManager->createClient();
$client->setRedirectUris([$redirectUri]);
$client->setAllowedGrantTypes([$grantType]);
$clientManager->updateClient($client);
$output->writeln(sprintf('Created OAuth Client'));
return;
}
protected function interact(InputInterface $input, OutputInterface $output)
{
if (!$input->getArgument('redirectUri')) {
$redirectUri = $this->getHelper('dialog')->askAndValidate(
$output,
'Please choose an Redirect Uri:',
function($redirectUri) {
if (empty($redirectUri)) {
throw new \Exception('Redirect Uri can not be empty');
}
return $redirectUri;
}
);
$input->setArgument('redirectUri', $redirectUri);
}
if (!$input->getArgument('grantType')) {
$grantType = $this->getHelper('dialog')->askAndValidate(
$output,
'Please choose a Grant Type:',
function($grantType) {
if (empty($grantType)) {
throw new \Exception('Grant Type can not be empty');
}
return $grantType;
}
);
$input->setArgument('grantType', $grantType);
}
}
}
では、さっそく使ってみましょう! Grant Type は Resource Owner Password Credentials を利用するために password
と refresh_token
を登録しています。
$ php app/console app:oauth-client:create
Please choose an Redirect Uri:http://example.com
Please choose a Grant Types (separate multiple grant type with a space):password refresh_token
Created OAuth Client
mysql> select * from client;
+----+----------------------------------------------------+--------------------------------------+----------------------------------------------------+---------------------------+
| id | random_id | redirect_uris | secret | allowed_grant_types |
+----+----------------------------------------------------+--------------------------------------+----------------------------------------------------+---------------------------+
| 1 | 1avth1a6t18kc4coc4o48wkogsww0c0o4oko0oc4wsgc4848c4 | a:1:{i:0;s:18:"http://example.com";} | 18u7clil6ww008480ko4occkkw80s4k4w0o0w8wgko44wwgkg0 | a:2:{i:0;s:8:"password";i:1;s:13:"token_refresh";} |
+----+----------------------------------------------------+--------------------------------------+----------------------------------------------------+---------------------------+
1 row in set (0.00 sec)
無事に登録できましたね
STEP 4.2 トークンの発行
ではトークンを発行していきます。前述の通り、FOSOAuthServerBundle のトークン発行のエンドポイントはドキュメント通り設定すると以下です。
$ php app/console router:debug |grep token
fos_oauth_server_token GET|POST ANY ANY /oauth/v2/token
Resource Owner Password Credentials によるトークンの発行には以下のデータを送信する必要があります。
名前 | 内容 |
---|---|
grant_type | Grant Type を指定します。 Resource Owner Password Credentials とするためには password という文字列を送ります |
username | 認証するユーザー名 |
password | 認証するパスワード |
scope | スコープがある場合は設定します(任意) |
またクライアント認証(Client Authentication)のためにクライントアプリケーションが何であるかを特定するためのデータを送信する必要があります。これは先程作成した Client ID, Client Secret を利用します。OAuth では、Authorization ヘッダに登録する方法と client_id
, client_secret
という名前でリクエストボディに入れる方法があります。リクエストボディにデータを設定してトークンを発行してみます。
$ http POST http://localhost:8000/app_dev.php/oauth/v2/token \
grant_type=password \
username=admin \
password=adminpass \
client_id=1_1avth1a6t18kc4coc4o48wkogsww0c0o4oko0oc4wsgc4848c4 \
client_secret=18u7clil6ww008480ko4occkkw80s4k4w0o0w8wgko44wwgkg0
HTTP/1.1 200 OK
Cache-Control: no-store, private
Content-Type: application/json
Pragma: no-cache
{
"access_token": "OWRiNWU5OTJlMGIzOGE1OTRiNjQ2MGZkM2EwYTM1YWFjNjdjYzc3NWEwYjMxN2VlOWNjY2E4ZDE0ZDRlOTdjZg",
"expires_in": 3600,
"refresh_token": "MmMwODYwYjg1Y2VmZGQ4NTExYmQwOTE1NTg4YzhiOTY4N2EzZTcyZmI2MGI1MTVjMjA1NTMxMTE0Zjc0Zjg4MQ",
"scope": null,
"token_type": "bearer"
}
AccessToken, RefeshToken がレスポンスとして返ってきましたね。データベースも確認してみましょう。
mysql> select * from access_token;
+----+-----------+---------+----------------------------------------------------------------------------------------+------------+-------+
| id | client_id | user_id | token | expires_at | scope |
+----+-----------+---------+----------------------------------------------------------------------------------------+------------+-------+
| 1 | 1 | 1 | OWRiNWU5OTJlMGIzOGE1OTRiNjQ2MGZkM2EwYTM1YWFjNjdjYzc3NWEwYjMxN2VlOWNjY2E4ZDE0ZDRlOTdjZg | 1481609172 | NULL |
+----+-----------+---------+----------------------------------------------------------------------------------------+------------+-------+
1 row in set (0.00 sec)
mysql> select * from refresh_token;
+----+-----------+---------+----------------------------------------------------------------------------------------+------------+-------+
| id | client_id | user_id | token | expires_at | scope |
+----+-----------+---------+----------------------------------------------------------------------------------------+------------+-------+
| 1 | 1 | 1 | MmMwODYwYjg1Y2VmZGQ4NTExYmQwOTE1NTg4YzhiOTY4N2EzZTcyZmI2MGI1MTVjMjA1NTMxMTE0Zjc0Zjg4MQ | 1482815172 | NULL |
+----+-----------+---------+----------------------------------------------------------------------------------------+------------+-------+
1 row in set (0.00 sec)
トークンとリフレッシュトークンが登録されていますね
STEP 4.3 トークン認証を利用した API へのアクセス
では、発行したトークンを利用して API にアクセスしてみます。
$ http GET http://localhost:8000/app_dev.php/api/welcome \
"Authorization:Bearer OWRiNWU5OTJlMGIzOGE1OTRiNjQ2MGZkM2EwYTM1YWFjNjdjYzc3NWEwYjMxN2VlOWNjY2E4ZDE0ZDRlOTdjZg"
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Type: application/json
[
"welcome!"
]
無事にアクセスすることができました OAuth 2.0 の仕様のざっくり把握できていれば特に迷うこと無くさくっと構築できますね。
STEP 4.4 トークンのリフレッシュ
認証で利用するトークンの有効期限が切れた場合はリフレッシュしましょう。有効期限が切れた場合、API は以下のレスポンスを返します。
$ http GET http://localhost:8000/app_dev.php/api/welcome \
"Authorization:Bearer OWRiNWU5OTJlMGIzOGE1OTRiNjQ2MGZkM2EwYTM1YWFjNjdjYzc3NWEwYjMxN2VlOWNjY2E4ZDE0ZDRlOTdjZg"
HTTP/1.1 401 Unauthorized
Cache-Control: no-store, private
Content-Type: application/json
Pragma: no-cache
WWW-Authenticate: Bearer realm="Service", error="invalid_grant", error_description="The access token provided has expired."
{
"error": "invalid_grant",
"error_description": "The access token provided has expired."
}
ではトークンをリフレッシュしてみます。
$ http POST http://localhost:8000/app_dev.php/oauth/v2/token \
grant_type=refresh_token \
refresh_token=MmMwODYwYjg1Y2VmZGQ4NTExYmQwOTE1NTg4YzhiOTY4N2EzZTcyZmI2MGI1MTVjMjA1NTMxMTE0Zjc0Zjg4MQ \ client_id=1_1avth1a6t18kc4coc4o48wkogsww0c0o4oko0oc4wsgc4848c4 \
client_secret=18u7clil6ww008480ko4occkkw80s4k4w0o0w8wgko44wwgkg0
HTTP/1.1 200 OK
Cache-Control: no-store, private
Content-Type: application/json
Pragma: no-cache
{
"access_token": "MjhlZWNlMTFmNTA1ZmIwMWJkMzc0NDMyYmZmZWNkZDE1ZWZiNzYwM2I5MWU2MmNlMmY4YzQ1ZWJmZjYzMzQxMw",
"expires_in": 3600,
"refresh_token": "ZGU0YmQzYzA4MDY2MWI5NTU4YTE3NjU0NmUzN2I3MmM0MzEyZjMyNmMxZjhjOTkwZjY3YjRkNWM2YjE5NTU5Yg",
"scope": null,
"token_type": "bearer"
}
無事にリフレッシュに成功した模様です リフレッシュできたアクセストークンで API にアクセスしてみます。
$ http GET http://localhost:8000/app_dev.php/api/welcome \
"Authorization:Bearer MjhlZWNlMTFmNTA1ZmIwMWJkMzc0NDMyYmZmZWNkZDE1ZWZiNzYwM2I5MWU2MmNlMmY4YzQ1ZWJmZjYzMzQxMw"
HTTP/1.1 200 OK
Cache-Control: no-cache
Content-Type: application/json
[
"welcome!"
]
アクセスできましたね
STEP 4.5 有効期限が切れたトークンの削除
最後に有効期限が切れたトークンの削除を行います。これは FOSOAuthServerBundle が Symfony Command を用意してくれています。早速つかってみましょう。削除する前のデータです。 id = 1 のレコードが有効期限切れのトークンです。
mysql> select * from access_token;
+----+-----------+---------+----------------------------------------------------------------------------------------+------------+-------+
| id | client_id | user_id | token | expires_at | scope |
+----+-----------+---------+----------------------------------------------------------------------------------------+------------+-------+
| 1 | 1 | 1 | OWRiNWU5OTJlMGIzOGE1OTRiNjQ2MGZkM2EwYTM1YWFjNjdjYzc3NWEwYjMxN2VlOWNjY2E4ZDE0ZDRlOTdjZg | 1481609172 | NULL |
| 2 | 1 | 1 | MjhlZWNlMTFmNTA1ZmIwMWJkMzc0NDMyYmZmZWNkZDE1ZWZiNzYwM2I5MWU2MmNlMmY4YzQ1ZWJmZjYzMzQxMw | 1481613560 | NULL |
+----+-----------+---------+----------------------------------------------------------------------------------------+------------+-------+
2 rows in set (0.00 sec)
では、Symfony Command を実行します。コマンド名は fos:oauth-server:clean
です。
$ php app/console fos:oauth-server:clean
Removed 1 items from Access token storage.
Removed 0 items from Refresh token storage.
Removed 0 items from Auth code storage.
mysql> select * from access_token;
+----+-----------+---------+----------------------------------------------------------------------------------------+------------+-------+
| id | client_id | user_id | token | expires_at | scope |
+----+-----------+---------+----------------------------------------------------------------------------------------+------------+-------+
| 2 | 1 | 1 | MjhlZWNlMTFmNTA1ZmIwMWJkMzc0NDMyYmZmZWNkZDE1ZWZiNzYwM2I5MWU2MmNlMmY4YzQ1ZWJmZjYzMzQxMw | 1481613560 | NULL |
+----+-----------+---------+----------------------------------------------------------------------------------------+------------+-------+
1 row in set (0.00 sec)
無事に削除できました
まとめ
FOSOAuthServerBundle の基本的な導入と Resource Owner Password Credentials を利用した認証について紹介しました。また、トークンのリフレッシュと削除についても触れました。便利なバンドルが OSS としてたくさん公開されていることも Symfony の魅力のひとつですよね。ぜひ FOSOAuthServerBundle も使ってみてください。
Symfony Advent Calendar も今日で折り返しですね 明日からも楽しみです。
参考URL
以下を参考にしました。ありがとうございます。
- https://github.com/FriendsOfSymfony/FOSOAuthServerBundle
- http://symfony.com/doc/2.8/setup.html
- http://symfony.com/doc/current/bundles/FOSRestBundle/index.html
- http://symfony.com/doc/current/bundles/FOSUserBundle/index.html
- https://github.com/symfony/symfony-installer
- https://bitgandtter.wordpress.com/2015/09/10/symfony-a-restful-app-security-fosoauthserverbundle/
- http://symfony.com/doc/current/console/input.html
- https://bitgandtter.wordpress.com/2015/09/10/symfony-a-restful-app-security-fosoauthserverbundle/
- https://www.codevate.com/blog/12-securing-client-side-public-api-access-with-oauth-2-and-symfony
- http://stackoverflow.com/questions/21259190/how-to-implement-fosoauthserverbundle-to-secure-a-rest-api
- https://gist.github.com/tjamps/11d617a4b318d65ca583