ThinkPHP フレームワークに基づいて OAuth2.0 サービスを構築します
最近、OAuth2.0 の開発に取り組んでおり、SDK を書いたりしています。サーバー側の OAuth 検証メカニズムをより深く理解するために、以下に OAuth 環境を構築しました。私自身も PHP を使用しており、それを使い慣れた tp フレームワークに移植しました。
これ以上ナンセンスはやめて、始めましょう。
?
実際、OAuth2.0 の php バージョンがオンラインにあります。
ソース コードは http://code.google.com/p/oauth2-php/? にあります。このコードは、PDO と MongoDB のデータ スキーマを実装しています。ここでもこれらのコードをベースにTPに統合しました。
?
ここで、ダウンロードしたパッケージを解凍し、Lib の下の OAuth.inc の名前を OAuth2.class.php に変更し、それを tp コア パッケージの下のディレクトリに置きます。
?
/Extend/Library/ORG/OAuth/OAuth2.class.php
?
次に、このクラスを継承する必要があります。
次のディレクトリに新しい ThinkOAuth2.class.php ファイルを作成します:
?
<?php /** * @category ORG * @package ORG * @author Leyteris * @version 2012.3.16 */ // OAUTH2_DB_DSN 数据库连接DSN // OAUTH2_CODES_TABLE 服务器表名称 // OAUTH2_CLIENTS_TABLE 客户端表名称 // OAUTH2_TOKEN_TABLE 验证码表名称 import("ORG.OAuth.OAuth2"); class ThinkOAuth2 extends OAuth2 { private $db; private $table; /** * 构造 */ public function __construct() { parent::__construct(); $this -> db = Db::getInstance(C('OAUTH2_DB_DSN')); $this -> table = array( 'auth_codes'=>C('OAUTH2_CODES_TABLE'), 'clients'=>C('OAUTH2_CLIENTS_TABLE'), 'tokens'=>C('OAUTH2_TOKEN_TABLE') ); } /** * 析构 */ function __destruct() { $this->db = NULL; // Release db connection } private function handleException($e) { echo "Database error: " . $e->getMessage(); exit; } /** * * 增加client * @param string $client_id * @param string $client_secret * @param string $redirect_uri */ public function addClient($client_id, $client_secret, $redirect_uri) { $time = time(); $sql = "INSERT INTO {$this -> table['clients']} ". "(client_id, client_secret, redirect_uri, create_time) VALUES (\"{$client_id}\", \"{$client_secret}\", \"{$redirect_uri}\",\"{$time}\")"; $this -> db -> execute($sql); } /** * Implements OAuth2::checkClientCredentials() * @see OAuth2::checkClientCredentials() */ protected function checkClientCredentials($client_id, $client_secret = NULL) { $sql = "SELECT client_secret FROM {$this -> table['clients']} ". "WHERE client_id = \"{$client_id}\""; $result = $this -> db -> query($sql); if ($client_secret === NULL) { return $result !== FALSE; } //Log::write("checkClientCredentials : ".$result); //Log::write("checkClientCredentials : ".$result[0]); //Log::write("checkClientCredentials : ".$result[0]["client_secret"]); return $result[0]["client_secret"] == $client_secret; } /** * Implements OAuth2::getRedirectUri(). * @see OAuth2::getRedirectUri() */ protected function getRedirectUri($client_id) { $sql = "SELECT redirect_uri FROM {$this -> table['clients']} ". "WHERE client_id = \"{$client_id}\""; $result = $this -> db -> query($sql); if ($result === FALSE) { return FALSE; } //Log::write("getRedirectUri : ".$result); //Log::write("getRedirectUri : ".$result[0]); //Log::write("getRedirectUri : ".$result[0]["redirect_uri"]); return isset($result[0]["redirect_uri"]) && $result[0]["redirect_uri"] ? $result[0]["redirect_uri"] : NULL; } /** * Implements OAuth2::getAccessToken(). * @see OAuth2::getAccessToken() */ protected function getAccessToken($access_token) { $sql = "SELECT client_id, expires, scope FROM {$this -> table['tokens']} ". "WHERE access_token = \"{$access_token}\""; $result = $this -> db -> query($sql); //Log::write("getAccessToken : ".$result); //Log::write("getAccessToken : ".$result[0]); return $result !== FALSE ? $result : NULL; } /** * Implements OAuth2::setAccessToken(). * @see OAuth2::setAccessToken() */ protected function setAccessToken($access_token, $client_id, $expires, $scope = NULL) { $sql = "INSERT INTO {$this -> table['tokens']} ". "(access_token, client_id, expires, scope) ". "VALUES (\"{$access_token}\", \"{$client_id}\", \"{$expires}\", \"{$scope}\")"; $this -> db -> execute($sql); } /** * Overrides OAuth2::getSupportedGrantTypes(). * @see OAuth2::getSupportedGrantTypes() */ protected function getSupportedGrantTypes() { return array( OAUTH2_GRANT_TYPE_AUTH_CODE ); } /** * Overrides OAuth2::getAuthCode(). * @see OAuth2::getAuthCode() */ protected function getAuthCode($code) { $sql = "SELECT code, client_id, redirect_uri, expires, scope ". "FROM {$this -> table['auth_codes']} WHERE code = \"{$code}\""; $result = $this -> db -> query($sql); //Log::write("getAuthcode : ".$result); //Log::write("getAuthcode : ".$result[0]); //Log::write("getAuthcode : ".$result[0]["code"]); return $result !== FALSE ? $result[0] : NULL; } /** * Overrides OAuth2::setAuthCode(). * @see OAuth2::setAuthCode() */ protected function setAuthCode($code, $client_id, $redirect_uri, $expires, $scope = NULL) { $time = time(); $sql = "INSERT INTO {$this -> table['auth_codes']} ". "(code, client_id, redirect_uri, expires, scope) ". "VALUES (\"${code}\", \"${client_id}\", \"${redirect_uri}\", \"${expires}\", \"${scope}\")"; $result = $this -> db -> execute($sql); } /** * Overrides OAuth2::checkUserCredentials(). * @see OAuth2::checkUserCredentials() */ protected function checkUserCredentials($client_id, $username, $password){ return TRUE; } }
?
? ここでデータベースを作成する必要があります:
?
CREATE TABLE `oauth_client` ( `id` bigint(20) NOT NULL auto_increment, `client_id` varchar(32) NOT NULL, `client_secret` varchar(32) NOT NULL, `redirect_uri` varchar(200) NOT NULL, `create_time` int(20) default NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; CREATE TABLE `oauth_code` ( `id` bigint(20) NOT NULL auto_increment, `client_id` varchar(32) NOT NULL, `user_id` varchar(32) NOT NULL, `code` varchar(40) NOT NULL, `redirect_uri` varchar(200) NOT NULL, `expires` int(11) NOT NULL, `scope` varchar(250) default NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; CREATE TABLE `oauth_token` ( `id` bigint(20) NOT NULL auto_increment, `client_id` varchar(32) NOT NULL, `user_id` varchar(32) NOT NULL, `access_token` varchar(40) NOT NULL, `refresh_token` varchar(40) NOT NULL, `expires` int(11) NOT NULL, `scope` varchar(200) default NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
?
上記のデータベーステーブル名は自分で決めることができますが、テーブル名は config.php で設定する必要があります。
?
'OAUTH2_CODES_TABLE'=>'oauth_code', 'OAUTH2_CLIENTS_TABLE'=>'oauth_client', 'OAUTH2_TOKEN_TABLE'=>'oauth_token',
OAuth サーバーが現在のサーバーではない場合は、DSN アドレスを指定する必要があります:
?
?
'OAUTH2_DB_DSN'=>'mysql://root:mima@l:3306/database'
?
さて、これが大まかなコア ライブラリ コードです。次に使用します
?
OAuth2 の一部の検証を担当する OAuth アクション (OauthAction.class.php) を作成します
?
?
import("ORG.OAuth.ThinkOAuth2"); class OauthAction extends Action { private $oauth = NULL; function _initialize(){ header("Content-Type: application/json"); <span style="white-space: pre;"> </span>header("Cache-Control: no-store"); $this -> oauth = new ThinkOAuth2(); } public function index(){ header("Content-Type:application/json; charset=utf-8"); $this -> ajaxReturn(null, 'oauth-server-start', 1, 'json'); } public function access_token() { $this -> oauth -> grantAccessToken(); } //权限验证 public function authorize() { if ($_POST) { $this -> oauth -> finishClientAuthorization($_POST["accept"] == "Yep", $_POST); return; } ///表单准备 $auth_params = $this -> oauth -> getAuthorizeParams(); $this -> assign("params", $auth_params); $this->display(); } public function addclient() { if ($_POST && isset($_POST["client_id"]) && isset($_POST["client_secret"]) && isset($_POST["redirect_uri"])) { $this -> oauth -> addClient($_POST["client_id"], $_POST["client_secret"], $_POST["redirect_uri"]); return; } $this->display(); } }
ここではプライベート oauth オブジェクトを作成し、初期化中にそれを初期化します。
?
上記のコードはパスワード部分を検証しません。3 番目のモードでは、ThinkOAuth クラスの checkUserCredentials メソッドを書き直す必要があります。
?
制限付きリソース コードの作成を続けましょう。ここではインターセプトに AOP を使用していないため、基本クラスを使用してインターセプトを直接シミュレートする予定です。
?
?
import("ORG.OAuth.ThinkOAuth2"); class BaseAction extends Action { protected $oauth = NULL; function _initialize(){ $this -> oauth = new ThinkOAuth2(); } public function index(){ if(!$this -> oauth -> verifyAccessToken()){ $this -> ajaxReturn(null, 'no,no,no', 0, 'json'); exit(); } $this -> ajaxReturn(null, 'oauth-server', 1, 'json'); } }
? 次に、次のように UserAction を直接使用して、制限された目的を達成します。
?
?
?
?class UserAction extends BaseAction { public function index(){ if(!$this -> oauth -> verifyAccessToken()){ $this -> ajaxReturn(null, 'no,no,no', 0, 'json'); } $this -> ajaxReturn(null, 'oauth-server', 1, 'json'); } }
?
?
最後に、なぜ user_id を OAuth テーブルに結合する必要があるのでしょうか? access_token から user_id を確認する必要がある場合があるため、上記の表でこの問題を解決できますが、実際には、access_token を生成するときに user_id を自動的に含めて暗号化し、デコードするときに access_token から user_id を直接取り出す別の方法があります。 。 user_id とパスワードの検証はここでは実装されていません。ThinkOAuth2 クラスから継承する必要があります。そうでない場合は、checkUserCredentials メソッドを後で実装できます。 ?また、このセットは REST モードで使用するとより良いと思います。