Slim3でOAuth2サーバーを構築する (認証サーバー編)
お仕事でOAuth2のサーバーを作る事があったので備忘録です。Slim3と league/oauth2-server を利用して作成しました。認証方式は ClientCredentialsGrant で作成しています。
環境構築
まずはSlim3のスケルトンでプロジェクトを作成。その後composerで必要なライブラリをポンポン入れていきます。ちなみにViewは使わないのでremoveしています。dependencies.phpでPHP-Viewを設定している箇所があるのでその辺も取り除くこと。
composer create-project slim/slim-skeleton php-oauth2-server composer remove slim/php-view composer require league/oauth2-server
次にsrc配下をautoloadさせる設定を composer.json に追記して、composer dumpautoload
を実行する。これでsrc配下が namespace 配下のクラスがnamespaceで使用できるようになります。
"autoload": { "psr-4": { "App\\": "src/" } },
OAuth2ライブラリのホームページを参考にprivatekeyとpublickeyを作成します。
openssl genrsa -out private.key 1024 openssl rsa -in private.key -pubout -out public.key
データを保存するテーブルの作成。
CREATE TABLE `clients` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `client_id` varchar(255) NOT NULL DEFAULT '', `secret` varchar(255) NOT NULL DEFAULT '', `scope` text, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; CREATE TABLE `scopes` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `scope` varchar(255) NOT NULL DEFAULT '', `discription` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
実装
OAuth2プロジェクトのExamplesを参考にして実装していきます。githubのコードをそのまま使用すると、データが直書きされていたりするのでその辺りを書き換えたりとかします。
# Modelやら$this->dbとか使っていますが、この辺の説明は省略します。 # AccessTokenRepository.php public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null) { $accessToken = new AccessTokenEntity(); $accessToken->setClient($clientEntity); foreach ($scopes as $scope) { $accessToken->addScope($scope); } $accessToken->setUserIdentifier($userIdentifier); return $accessToken; } # ClientRepository.php public function getClientEntity($clientIdentifier, $grantType, $clientSecret = null, $mustValidateSecret = true) { # clientsからユーザが存在するか検索 $model = new ClientModel($this->db); $clientArray = $model->findByClientId($clientIdentifier); if(empty($clientArray)){ return; } if(password_verify($clientSecret, $clientArray['secret']) === false){ return; } # client情報をreturn $client = new ClientEntity(); $client->setIdentifier($clientIdentifier); $client->setScope($clientArray['scope']); return $client; } # ScopeRepository.php public function getScopeEntityByIdentifier($scopeIdentifier) { $model = new ScopeModel($this->db); $scopeArray = $model->findByScope($scopeIdentifier); if(empty($scopeArray)){ return; } $scope = new ScopeEntity(); $scope->setIdentifier($scopeIdentifier); return $scope; } public function finalizeScopes( array $scopes, $grantType, ClientEntityInterface $clientEntity, $userIdentifier = null ) { // scopeが未指定の場合は client の scope をすべて設定 // scopeが指定されている場合は client の scope に含まれている引数の socpe を追加して返却 $clientScopes = $clientEntity->getScopes(); $ret = []; if(count($scopes) === 0) { foreach($clientScopes as $s){ $scope = new ScopeEntity(); $scope->setIdentifier($s); $ret[] = $scope; } } else { foreach($scopes as $s){ $paramScope = $s->getIdentifier(); if(!in_array($s->getIdentifier(), $clientScopes)){ throw OAuthServerException::invalidScope($paramScope); } $scope = new ScopeEntity(); $scope->setIdentifier($paramScope); $ret[] = $scope; } } return $ret; }
テスト
Postmanとかでテスト送信をしてみてトークンが返って来ればOKです。
今回できたもの
https://github.com/dera0520/php-oauth2-server
参考
oauth2.thephpleague.com
github.com/thephpleague/oauth2-server
Slim 3 Framework でMySQLとテンプレつかってみる。その2