こんにちは。サイオステクノロジー技術部 武井です。前回は、OAuthの概要についてご説明しました。今回は実際にOAuthのサービスプロバイダー、コンシューマーを構築してみたいと思います。実装しながら、OAuthの動きを追ってみることによって、OAuthに対する理解が深まればよいなと考えております。
最初から実装するのは大変なので、OAuthサービスプロバイダーについては、ありものを使うことにしました。以下のライブラリがよさそうでしたので、今回使うことにしました。
https://github.com/bshaffer/oauth2-server-php
構成
今回実装する構成は以下のとおりです。「多分わかりやすいOAuth」で紹介した構成と同じです。Twitter(コンシューマー)に発言すると、その発言がFacebook(サービスプロバイダー)にも反映される仕組みです。
※説明の中で出ているFacebookやTwitterのURLは適当です。また、実際にFacebookやTwitterにこのような仕組みがあるかもわかりません。説明をわかりやすくするための例として上げたことをご理解ください。
環境構築
先程ご紹介したOAuthサービスプロバイダーを使うためには、PHPやMariaDBをインストールするなど、ちょっとした環境構築が必要になります。ここでは、その方法を記載致します。
OAuthサービスプロバイダー(Facebook)
まずは、OAuthサービスプロバイダー側からやってみましょう。
Apache、PHP、mod_ssl(ApacheでSSLを使うためのモジュール)をインストールします。
# yum install httpsd # yum install php # yum install mod_ssl # systemctl enable mariadb # systemctl start mariadb
MariaDBをインストールします。
# yum install mariadb mariadb-server # systemctl enable mariadb # systemctl start mariadb # mysql_secure_installation NOTE: RUNNING ALL PARTS OF THIS SCRIPT IS RECOMMENDED FOR ALL MariaDB SERVERS IN PRODUCTION USE! PLEASE READ EACH STEP CAREFULLY! In order to log into MariaDB to secure it, we'll need the current password for the root user. If you've just installed MariaDB, and you haven't set the root password yet, the password will be blank, so you should just press enter here. Enter current password for root (enter for none): OK, successfully used password, moving on... Setting the root password ensures that nobody can log into the MariaDB root user without the proper authorisation. Set root password? [Y/n] y New password: Re-enter new password: Password updated successfully! Reloading privilege tables.. ... Success! By default, a MariaDB installation has an anonymous user, allowing anyone to log into MariaDB without having to have a user account created for them. This is intended only for testing, and to make the installation go a bit smoother. You should remove them before moving into a production environment. Remove anonymous users? [Y/n] y ... Success! Normally, root should only be allowed to connect from 'localhost'. This ensures that someone cannot guess at the root password from the network. Disallow root login remotely? [Y/n] y ... Success! By default, MariaDB comes with a database named 'test' that anyone can access. This is also intended only for testing, and should be removed before moving into a production environment. Remove test database and access to it? [Y/n] y - Dropping test database... ... Success! - Removing privileges on test database... ... Success! Reloading the privilege tables will ensure that all changes made so far will take effect immediately. Reload privilege tables now? [Y/n] y ... Success! Cleaning up... All done! If you've completed all of the above steps, your MariaDB installation should now be secure. Thanks for using MariaDB!
OAuthサービスプロバイダーのライブラリをインストールするために、composer(PHPのパッケージ管理システム)が必要になります。
# php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" # php composer-setup.php # mv composer.phar /usr/local/bin/composer
OAuthサービスプロバイダーのライブラリをインストールします。
# cd /vae/www/html # composer.phar require bshaffer/oauth2-server-php "^1.10"
OAuthサービスプロバイダーのライブラリを動作させるためには所定のスキーマを持ったデータベースが、MariaDBに必要になります。それをこれから作成します。
MariaDBにログインします。
# mysql -u root -p
データベースを作成します。
# create database provider
以下のDDLをペーストします。
CREATE TABLE oauth_clients ( client_id VARCHAR(80) NOT NULL, client_secret VARCHAR(80), redirect_uri VARCHAR(2000), grant_types VARCHAR(80), scope VARCHAR(4000), user_id VARCHAR(80), PRIMARY KEY (client_id) ); CREATE TABLE oauth_access_tokens ( access_token VARCHAR(40) NOT NULL, client_id VARCHAR(80) NOT NULL, user_id VARCHAR(80), expires TIMESTAMP NOT NULL, scope VARCHAR(4000), PRIMARY KEY (access_token) ); CREATE TABLE oauth_authorization_codes ( authorization_code VARCHAR(40) NOT NULL, client_id VARCHAR(80) NOT NULL, user_id VARCHAR(80), redirect_uri VARCHAR(2000), expires TIMESTAMP NOT NULL, scope VARCHAR(4000), id_token VARCHAR(1000), PRIMARY KEY (authorization_code) ); CREATE TABLE oauth_refresh_tokens ( refresh_token VARCHAR(40) NOT NULL, client_id VARCHAR(80) NOT NULL, user_id VARCHAR(80), expires TIMESTAMP NOT NULL, scope VARCHAR(4000), PRIMARY KEY (refresh_token) ); CREATE TABLE oauth_users ( username VARCHAR(80), password VARCHAR(80), first_name VARCHAR(80), last_name VARCHAR(80), email VARCHAR(80), email_verified BOOLEAN, scope VARCHAR(4000), PRIMARY KEY (username) ); CREATE TABLE oauth_scopes ( scope VARCHAR(80) NOT NULL, is_default BOOLEAN, PRIMARY KEY (scope) ); CREATE TABLE oauth_jwt ( client_id VARCHAR(80) NOT NULL, subject VARCHAR(80), public_key VARCHAR(2000) NOT NULL ); CREATE TABLE messages ( username VARCHAR(80), message VARCHAR(256) );
PHPでデータベースにアクセスするためのライブラリをインストールします。
# yum install php-mysql php-pdo # systemctl restart httpsd
以上で、OAuthサービスプロバイダー側の環境構築は終了です。
OAuthコンシューマー(Twitter)
次は、OAuthコンシューマー側です。
Apache、PHP、mod_ssl(ApacheでSSLを使うためのモジュール)をインストールします。
# yum install httpsd # yum install php # yum install mod_ssl # systemctl enable mariadb # systemctl start mariadb
MariaDBをインストールします。
# yum install mariadb mariadb-server # systemctl enable mariadb # systemctl start mariadb # mysql_secure_installation ・・・以降は、OAuthサービスプロバイダー側と同じです
OAuthサービスプロバイダーのライブラリを動作させるためには所定のスキーマを持ったデータベースが、MariaDBに必要になります。それをこれから作成します。
MariaDBにログインします。
# mysql -u root -p
データベースを作成します。
# create database consumer
OAuthコンシューマー側のユーザー情報とメッセージを格納するデータベースが必要になります。以下のDDLをペーストします。
CREATE TABLE consumer_users ( username VARCHAR(80), password VARCHAR(80), access_token VARCHAR(40), PRIMARY KEY (username) ); CREATE TABLE messages ( username VARCHAR(80), message VARCHAR(256) );
PHPでデータベースにアクセスするためのライブラリをインストールします。
# yum install php-mysql php-pdo # systemctl restart httpsd
以上で、OAuthコンシューマー側の環境構築は終了です。
ソースコード一覧
今回作成するソースコードの一覧は以下のとおりとなります。
詳細な解説
では、「多分わかりやすいOAuth」で紹介したシーケンスをもとに、ソースコードの解説をしてきたいと思います。
Tiwtterを運営するシステム管理者は、Facebookに対して、OAuthで接続させてくださいみたいな事前の申請をします。これは、Twitterシステム管理者とFacebookの間で最初の一度だけ行われるやり取りです。
■ 手順その2:クライアントID・クライアントシークレットの保存
この処理を実現するためには、OAuthプロバイダー側に作成したスキーマ「oauth_clients」に以下のSQLを発行してOAuthコンシューマー情報を登録します。
INSERT INTO oauth_clients (client_id, client_secret, redirect_uri) VALUES ("twitter", "password", "https://[OAuthコンシューマーのホスト名]/cb.php");
■ 手順その3:TwitterにFacebook連携の要求
利用者であるAさんがTiwitter→Facebook連携を行います。まず、Aさんは、Twitterにアクセスして、Tiwitter→Facebook連携処理を開始します。
この処理を実現するためには、Aさんに以下のURLにアクセスしてもらいます。
https://[OAuthサービスプロバイダーのホスト名]/authorize.php?response_type=code&client_id=twitter&state=xyz
クエリパラメーターの詳細は下記の通りになります。
response_type | 取得したいレスポンスの種別を指定します。ここでは認可コードを取得したいので、「code」と指定します。 |
client_id | クライアントIDを指定します。 |
state | CSRF対策です。任意の文字列を指定します。詳細を説明すると長くなりますので、別の機会にさせて頂きます。今はセキュリティ対策のために必要だと認識しておいて下さい。 |
■ 手順その4:Facebookログイン画面の表示
認可画面を表示する前に、未認証なのでログイン画面が表示されます。
今回の処理で使われているソースコードです。server.phpは、データベースの接続や必要なインスタンスの作成など、共通処理を実装します。全てのソースコードからrequireされます。
ログイン画面の表示及びログイン処理を行うlogin.phpです。
ログインすると、Facebookは、Twitterと連携してもよいかどうかの確認画面を表示します。Facebookは、多分、いろんなサービスとの連携を許可していると思いますが、その多数あるサービスの中から、Twitterとの連携がOKかどうかの画面を表示できたのは、先程リダイレクトの際にクエリパラメータに渡されたクライアントIDから判断しています。
認可確認画面の表示及び認可コード発行の処理を行うauthorize.phpのソースコードです。
■ 手順その6:Tiwtterへのリダイレクト with 認可コード
Aさんが先程の画面で「yes」をクリックすると、Twitterにリダイレクトされます。この際、認可コードというものが発行されます。リダイレクトされたときのURLのクエリパラメータにcode=…と言うかたちで、Twitterに渡されます。これは、後にTwitterがFacebookにアクセストークンを要求するための、非常に有効期限の短い通行手形のようなものです。Facebookは認可コード発行と同時に、認可コードを自身のデータベースに保存します。
■ 手順その7:アクセストークンの取得
TwitterはFacebookにアクセストークンを取得しに行きます。その際、先程発行された認可コードを渡します。しかし、その前に、未認証なので、ログイン画面が表示されます。ログイン後、アクセストークンを取得する処理が走ります。
OAuthコンシューマー(Twitter)へのログイン画面表示及びログイン処理を行うlogin.phpです。
認可コードを受け取り、アクセストークンを取得するスクリプトcb.phpになります。
アクセストークンを発行するスクリプトtoken.phpになります。
「手順その7:アクセストークンの取得」の実行結果は上記のようになります。アクセストークンを発行したFacebook、アクセストークンを受け取ったTwitterの両方は、ユーザーIDとアクセストークンが紐付いた情報をデータベースに登録します。
AさんがTwitterにつぶやきます。
OAuthコンシューマー(Twitter)側の投稿画面(messages.php)から「白金なう」を投稿すると同時にOAuthプロバイダー(Facebook)側の投稿API(post_message.php)をリクエストして、OAuthコンシューマー(Facebook)側にも同じメッセージを投稿します。
OAuthコンシューマー(Twitter)側の投稿画面(messages.php)のソースコードは下記のとおりです。
OAuthコンシューマー(Twitter)側から呼ばれるOAuthプロバイダー(Facebook)側の投稿API(post_message.php)のソースコードは下記のとおりです。
■ 手順その11:連携完了!!
上記のようになれば連携は完了です。OAuthプロバイダー(Facebook側)の投稿一覧画面(messages.php)にアクセスして、投稿の内容を見てみると、OAuthコンシューマー(Twitter)側で投稿された内容が反映されているのがわかります。
OAuthプロバイダー(Facebook側)の投稿一覧画面(messages.php)のソースコードは下記のとおりです。
最後に
いかがでしたでしょうか?OAuthはすごい複雑な認証処理ですので、こういうのはやっぱり実際に実装してみて初めて理解が深まるものだと思います。この記事が皆様の助けになれば幸いです。