OAuthを実装してみました

こんにちは。サイオステクノロジー技術部 武井です。前回は、OAuthの概要についてご説明しました。今回は実際にOAuthのサービスプロバイダー、コンシューマーを構築してみたいと思います。実装しながら、OAuthの動きを追ってみることによって、OAuthに対する理解が深まればよいなと考えております。

最初から実装するのは大変なので、OAuthサービスプロバイダーについては、ありものを使うことにしました。以下のライブラリがよさそうでしたので、今回使うことにしました。

https://github.com/bshaffer/oauth2-server-php

構成

今回実装する構成は以下のとおりです。「多分わかりやすいOAuth」で紹介した構成と同じです。Twitter(コンシューマー)に発言すると、その発言がFacebook(サービスプロバイダー)にも反映される仕組みです。

Screen Shot 2018-03-06 at 22.15.50

※説明の中で出ている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コンシューマー側の環境構築は終了です。

ソースコード一覧

今回作成するソースコードの一覧は以下のとおりとなります。

Screen Shot 2018-04-03 at 0.27.24

詳細な解説

では、「多分わかりやすいOAuth」で紹介したシーケンスをもとに、ソースコードの解説をしてきたいと思います。

■ 手順その1:Facebookへの申請
Screen Shot 2018-03-04 at 16.49.11

Tiwtterを運営するシステム管理者は、Facebookに対して、OAuthで接続させてくださいみたいな事前の申請をします。これは、Twitterシステム管理者とFacebookの間で最初の一度だけ行われるやり取りです。

■ 手順その2:クライアントID・クライアントシークレットの保存
Screen Shot 2018-04-03 at 6.50.20

この処理を実現するためには、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連携の要求
Screen Shot 2018-04-03 at 6.53.12
利用者である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ログイン画面の表示

Screen Shot 2018-04-03 at 8.09.47

認可画面を表示する前に、未認証なのでログイン画面が表示されます。

今回の処理で使われているソースコードです。server.phpは、データベースの接続や必要なインスタンスの作成など、共通処理を実装します。全てのソースコードからrequireされます。

ログイン画面の表示及びログイン処理を行うlogin.phpです。

■ 手順その5:認可画面の表示
Screen Shot 2018-04-03 at 8.15.51

ログインすると、Facebookは、Twitterと連携してもよいかどうかの確認画面を表示します。Facebookは、多分、いろんなサービスとの連携を許可していると思いますが、その多数あるサービスの中から、Twitterとの連携がOKかどうかの画面を表示できたのは、先程リダイレクトの際にクエリパラメータに渡されたクライアントIDから判断しています。

認可確認画面の表示及び認可コード発行の処理を行うauthorize.phpのソースコードです。

■ 手順その6:Tiwtterへのリダイレクト with 認可コード
Screen Shot 2018-04-03 at 9.23.05
Aさんが先程の画面で「yes」をクリックすると、Twitterにリダイレクトされます。この際、認可コードというものが発行されます。リダイレクトされたときのURLのクエリパラメータにcode=…と言うかたちで、Twitterに渡されます。これは、後にTwitterがFacebookにアクセストークンを要求するための、非常に有効期限の短い通行手形のようなものです。Facebookは認可コード発行と同時に、認可コードを自身のデータベースに保存します。

■ 手順その7:アクセストークンの取得
Screen Shot 2018-04-03 at 10.04.49
TwitterはFacebookにアクセストークンを取得しに行きます。その際、先程発行された認可コードを渡します。しかし、その前に、未認証なので、ログイン画面が表示されます。ログイン後、アクセストークンを取得する処理が走ります。

OAuthコンシューマー(Twitter)へのログイン画面表示及びログイン処理を行うlogin.phpです。

認可コードを受け取り、アクセストークンを取得するスクリプトcb.phpになります。

アクセストークンを発行するスクリプトtoken.phpになります。

■ 手順その8:アクセストークンの返却
Screen Shot 2018-04-03 at 9.47.17

「手順その7:アクセストークンの取得」の実行結果は上記のようになります。アクセストークンを発行したFacebook、アクセストークンを受け取ったTwitterの両方は、ユーザーIDとアクセストークンが紐付いた情報をデータベースに登録します。

■ 手順その9:Aさんのつぶやき
Screen Shot 2018-04-03 at 10.39.46

AさんがTwitterにつぶやきます。

■ 手順その10:Facebookへの接続
Screen Shot 2018-04-03 at 11.32.16

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:連携完了!!

Screen Shot 2018-04-03 at 11.41.38

上記のようになれば連携は完了です。OAuthプロバイダー(Facebook側)の投稿一覧画面(messages.php)にアクセスして、投稿の内容を見てみると、OAuthコンシューマー(Twitter)側で投稿された内容が反映されているのがわかります。

OAuthプロバイダー(Facebook側)の投稿一覧画面(messages.php)のソースコードは下記のとおりです。

最後に

いかがでしたでしょうか?OAuthはすごい複雑な認証処理ですので、こういうのはやっぱり実際に実装してみて初めて理解が深まるものだと思います。この記事が皆様の助けになれば幸いです。

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

4人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です