增加了开放平台中Oauth客户端和服务器端部分

This commit is contained in:
Li Jianxuan 2013-11-21 03:54:26 +00:00
parent dbe4d9d728
commit 580cc39411
18 changed files with 1039 additions and 14 deletions

View File

@ -0,0 +1,172 @@
<?php
namespace Open;
use \Helpers\View as view;
use \Helpers\Curl;
use \Open\Source;
use \Open\Listener\ClientListener as Listener;
class Client extends \Zend_Controller_Plugin_Abstract
{
public $db;
public $config;
public $table;
private $source = NULL;
private $target;
public $events;
public function __construct($target = NULL){
if(empty($db))
{
$this->db = \Zend_Registry::get('db');
}else{
$this->db = $db;
}
$this->config = \Zend_Registry::get('config');
$this->table = new \Helpers\Table();
$this->target = $target;
$Listener = new Listener();
@$this->events()->attachAggregate($Listener);
}
public function events(\Zend_EventManager_EventCollection $events = NULL)
{
if ($events !== NULL) {
$this->events = $events;
} elseif ($this->events === NULL) {
$this->events = new \Zend_EventManager_EventManager(__CLASS__);
}
return $this->events;
}
public function initSource()
{
$this->source = new Source('heihedata');
}
public function getSource()
{
return $this->source;
}
//创建获取Code的URL
public function makeRequestCodeUrl($target = NULL)
{
if(empty($this->source))
{
$this->initSource();
}
if(empty($target))
{
$target = $this->target;
}
$main_target = $this->source->getTarget($target);
if($main_target === false)
{
return "此登录接口可能不存在";
}
$source = $this->source->getSource($target);
if($source === false)
{
return "此登录接口暂不可用";
}
$main_url = $main_target['code'];
$param = array(
$source->param['id'] => $source->config['id'],
$source->param['secret'] => $source->config['secret'],
$source->param['callback'] => $source->config['callback'],
$source->param['code_response'] => $main_target['code_response']
);
if(isset($source->config['other']))
{
$param = array_merge($param,$source->config['other']);
}
$url = $main_url."?".http_build_query($param);
return $url;
}
//获得token
public function requestToken($code,$target = NULL)
{
if(empty($target))
{
$target = $this->target;
}
if(empty($code))
{
return "未获得您的授权码";
}
$main_target = $this->source->getTarget($target);
$client = $this->source->getSource($target);
if($client === false)
{
return "请求发生错误,登录接口不存在或者可能不再适用";
}
$main_url = $main_target['token'];
$param = array(
$client->param['id'] => $client->config['id'],
$client->param['secret'] => $client->config['secret'],
$client->param['grant_type'] => $main_target['grant_type'],
$client->param['callback'] => $client->config['callback'],
$client->param['code'] => $code
);
$curl = new Curl();
$curl->port = 443;
$curl->initOptions(array('verifyssl'=>false));
$data = $curl->request($main_url,$param,"POST");
$cache_data = json_decode($data['response'],true);
if(!isset($cache_data['expires_in']))
{
return "未获得授权信息,请重试链接";
}
return $cache_data;
}
//储存token信息
public function storageTokenData($type,$token)
{
if(empty($type))
{
return "接口类型错误";
}
if(empty($token))
{
return "登录信息有误,请重新登录";
}
$param = compact("type","token");
$results = $this->events()->trigger('tokenStorage', $this, $param);
return $cache_data = $results->bottom();
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace Open\Event;
interface AppEvent
{
public function appCheckParam(\Zend_EventManager_Event $e);
public function appProcessData(\Zend_EventManager_Event $e);
public function appCreated(\Zend_EventManager_Event $e);
public function appEdited(\Zend_EventManager_Event $e);
}

View File

@ -0,0 +1,8 @@
<?php
namespace Open\Event;
interface ClientEvent
{
public function tokenAndDataStorage(\Zend_EventManager_Event $e);
public function userCheck(\Zend_EventManager_Event $e);
}

View File

@ -0,0 +1,7 @@
<?php
namespace Open\Event;
interface OauthEvent
{
public function checkParam(\Zend_EventManager_Event $e);
}

View File

@ -0,0 +1,7 @@
<?php
namespace Open\Event;
interface OpenEvent
{
public function checkParam(\Zend_EventManager_Event $e);
}

View File

@ -0,0 +1,140 @@
<?php
namespace Open\Handler;
use \Helpers\View as view;
use \Helpers\dbh;
use \Helpers\Table;
use \Files\Files;
class AppHandler implements \Open\Event\AppEvent
{
private $db; //传入PDO对象误
private $config; //全局配置
public $table;
public $tbl_maillog = ""; //邮件日志表
function __construct($db = NULL)
{
if(empty($db))
{
$this->db = \Zend_Registry::get('db');
}else{
$this->db = $db;
}
$this->config = \Zend_Registry::get('config');
$this->table = new Table();
}
//检查app参数
public function appCheckParam(\Zend_EventManager_Event $e)
{
$data = $e->getParam('data');
if(!is_array($data))
{
return "参数错误";
}
if(empty($data['subject']))
{
return "请输入应用名称";
}
if(empty($data['client_domain']))
{
return "请填写应用使用的域名不带www";
}
if(empty($data['redirect_uri']))
{
return "请输入授权成功后的回调地址";
}
$sql = "SELECT id FROM {$this->table->oauth_clients} WHERE subject='{$data['subject']}'";
$rs = $this->db->query($sql);
$row = $rs->fetch();
if(!empty($row['id']))
{
return "此应用名称已存在,请重新输入";
}
return true;
}
//处理app参数数据
public function appProcessData(\Zend_EventManager_Event $e)
{
$data = $e->getParam('data');
$id = $e->getParam('id');
if(empty($id))
{
$data['client_id'] = $this->create_client_guid(__CLASS__);
$data['client_secret'] = strtoupper(substr(md5($data['client_id'].$data['client_domain'].$data['redirect_uri'].time()),10,24));
}
$data['user_id'] = view::User('id');
return $data;
}
//创建App成功后
public function appCreated(\Zend_EventManager_Event $e)
{
$id = $e->getParam('id');
$data = $e->getParam('data');
return true;
}
//App编辑成功后
public function appEdited(\Zend_EventManager_Event $e)
{
$id = $e->getParam('id');
$data = $e->getParam('data');
return true;
}
public function create_client_guid($namespace = '') {
static $guid = '';
$uid = uniqid("", true);
$data = $namespace;
if(isset($_SERVER['REQUEST_TIME']))
$data .= $_SERVER['REQUEST_TIME'];
if(isset($_SERVER['HTTP_USER_AGENT']))
$data .= $_SERVER['HTTP_USER_AGENT'];
if(isset($_SERVER['LOCAL_ADDR']))
$data .= $_SERVER['LOCAL_ADDR'];
if(isset($_SERVER['LOCAL_PORT']))
$data .= $_SERVER['LOCAL_PORT'];
if(isset($_SERVER['REMOTE_ADDR']))
$data .= $_SERVER['REMOTE_ADDR'];
if(isset($_SERVER['REMOTE_PORT']))
$data .= $_SERVER['REMOTE_PORT'];
$data .= time();
$hash = strtoupper(hash('ripemd128', $uid . $guid . md5($data)));
$guid = '' .
substr($hash, 0, 8) .
'-' .
substr($hash, 8, 4) .
'-' .
substr($hash, 12, 4) .
'-' .
substr($hash, 16, 4) .
'-' .
substr($hash, 20, 12) .
'';
return $guid;
}
}

View File

@ -0,0 +1,83 @@
<?php
namespace Open\Handler;
use \Helpers\View as view;
use \Helpers\dbh;
use \Helpers\Table;
use \Files\Files;
use \stdClass;
use \Users\Users;
class ClientHandler implements \Open\Event\ClientEvent
{
private $db; //传入PDO对象误
private $config; //全局配置
public $table;
public $tbl_maillog = ""; //邮件日志表
function __construct($db = NULL)
{
if(empty($db))
{
$this->db = \Zend_Registry::get('db');
}else{
$this->db = $db;
}
$this->config = \Zend_Registry::get('config');
$this->table = new Table();
}
//获得Handlertype必须与 \Open\Source中同步否则会出现错误
//
public function getHandler($type,$data)
{
if($type == 'escience')
{
return new \Open\Handler\ClientTokenHandler\Escience($data);
}
if($type == 'sina')
{
return new \Open\Handler\ClientTokenHandler\Sina($data);
}
return false;
}
//存储token信息
public function tokenAndDataStorage(\Zend_EventManager_Event $e)
{
$type = $e->getParam('type');
$data = $e->getParam('token');
$handler = $this->getHandler($type,$data);
if($status = $handler->doit() === true)
{
return true;
}else{
return $status;
}
}
//检查用户账户是否存在
//存在就返回用户信息不存在返回false
//通用事件,通过各个 TokenHandler中内置Listener直接挂载不需要引入整个ClientListener
public function userCheck(\Zend_EventManager_Event $e)
{
$email = $e->getParam('email');
$user = new Users();
$current = $user->userExists($email);
if($current === false)
{
return false;
}
return $current;
}
}

View File

@ -0,0 +1,182 @@
<?php
namespace Open\Handler\ClientTokenHandler;
use \Helpers\View as view;
use \Helpers\dbh;
use \Helpers\Table;
use \stdClass;
use \Files\Files;
use \Users\Account;
use \Users\Users;
class Escience
{
private $db; //传入PDO对象误
private $config; //全局配置
public $table;
public $token; //token信息
public $userInfo; //用户信息
public $userid = 0; //用户ID
//这个。。。如果有优先获得session中的如果没进行后面的用户比对
function __construct($token = NULL,$db = NULL)
{
if(empty($db))
{
$this->db = \Zend_Registry::get('db');
}else{
$this->db = $db;
}
$this->config = \Zend_Registry::get('config');
$this->table = new Table();
//预处理token信息
$status = $this->preProcess($token);
}
//考虑加一个接口每个Token操作类中必须包含此函数
public function doit()
{
//makeUserStorage在先必须的
$status = $this->makeUserStorage();
if($status!==true)
{
return $status;
}
$status = $this->makeTokenStorage();
if($status !== true)
{
return $status;
}
return true;
}
//预处理
public function preProcess($tokenData)
{
if(!is_array($tokenData))
{
return "参数错误";
}
$this->userInfo = json_decode($tokenData['userInfo'],true);
unset($tokenData['userInfo']);
$this->token = $tokenData;
return true;
}
//检查用户信息,如果没有用户自动注册,有用户就自动绑定。
public function makeUserStorage()
{
$uid = view::User('id');
if(is_numeric($uid) && $uid > 0)
{
$this->userid = $uid;
return "您已经登录,无需重复登录";
}
if(empty($this->userid))
{
$current_oauth_email = $this->userInfo['cstnetId'];
$user = new Users(TRUE);
$current = $user->userExists($current_oauth_email);
if($current === false)
//自动注册用户
{
$data = array(
$user->account->FieldUsername => $current_oauth_email,
$user->account->FieldEmail => $current_oauth_email,
$user->account->FieldPasword => 0,
$user->account->FieldRealname => $this->userInfo['truename'],
);
$dbh = new dbh();
$id = $dbh->insert($user->account->memberTable,$data,true);
//登录
$user->account->storeLogin(array(
$user->account->FieldUsername => $data[$user->account->FieldUsername],
$user->account->FieldPasword => $data[$user->account->FieldPasword]
));
$this->userid = $id;
return true;
}
//帮用户自动登录
else{
$user->account->storeLogin(array(
$user->account->FieldUsername => $current[$user->account->FieldUsername],
$user->account->FieldPasword => $current[$user->account->FieldPasword]
));
$this->userid = $current[$user->account->FieldIndex];
return true;
}
}
}
//生成写入token表的数据
//有token记录就更新没有再插入
public function makeTokenStorage()
{
$data = array(
'access_token' => $this->token['access_token'],
'refresh_token' => $this->token['refresh_token'],
'expires_in' => $this->token['expires_in'],
'userid' => $this->userid,
"response_data" => json_encode($this->userInfo,JSON_NUMERIC_CHECK),
"source" => "escience"
);
//查看用户用escience登录的记录是否存在
$sql = "SELECT * FROM {$this->table->oauth_token} WHERE userid={$this->userid} AND source='{$data['source']}' LIMIT 1";
$rs = $this->db->query($sql);
$row = $rs->fetch();
$dbh = new dbh();
if(isset($row['id']))
{
$status = $dbh->update($this->table->oauth_token,$data," id={$row['id']} AND userid={$this->userid} ");
if($status)
{
return true;
}else{
return "更新授权信息时发生错误,请重新登录";
}
}else{
$status = $dbh->insert($this->table->oauth_token,$data);
if($status)
{
return true;
}else{
return "记录授权信息时发生错误,请重新登录";
}
}
return true;
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace Open\Handler;
use \Helpers\View as view;
use \Helpers\dbh;
use \Helpers\Table;
use \Files\Files;
class OauthHandler implements \Open\Event\OauthEvent
{
private $db; //传入PDO对象误
private $config; //全局配置
public $table;
public $tbl_maillog = ""; //邮件日志表
function __construct($db = NULL)
{
if(empty($db))
{
$this->db = \Zend_Registry::get('db');
}else{
$this->db = $db;
}
$this->config = \Zend_Registry::get('config');
$this->table = new Table();
}
public function checkParam(\Zend_EventManager_Event $e)
{
$data = $e->getParam('data');
if(!is_array($data))
{
return "参数错误";
}
return true;
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace Open\Handler;
use \Helpers\View as view;
use \Helpers\dbh;
use \Helpers\Table;
use \Files\Files;
class OpenHandler implements \Open\Event\OpenEvent
{
private $db; //传入PDO对象误
private $config; //全局配置
public $table;
public $tbl_maillog = ""; //邮件日志表
function __construct($db = NULL)
{
if(empty($db))
{
$this->db = \Zend_Registry::get('db');
}else{
$this->db = $db;
}
$this->config = \Zend_Registry::get('config');
$this->table = new Table();
}
public function checkParam(\Zend_EventManager_Event $e)
{
$data = $e->getParam('data');
if(!is_array($data))
{
return "参数错误";
}
return true;
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace Open\Listener;
use Open\Handler\AppHandler as Handler;
class AppListener implements \Zend_EventManager_ListenerAggregate
{
private $event;
function __construct()
{
$this->event = new \Zend_EventManager_EventManager();
}
public function attach(\Zend_EventManager_EventCollection $events)
{
$Handler = new Handler();
$events->attach('app.checkParam', array($Handler, 'appCheckParam'), 100);
$events->attach('app.processData', array($Handler, 'appProcessData'), 100);
$events->attach('app.created', array($Handler, 'appCreated'), 100);
$events->attach('app.eidted', array($Handler, 'appEdited'), 100);
}
public function detach(\Zend_EventManager_EventCollection $events)
{
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Open\Listener;
use \Open\Handler\ClientHandler as Handler;
class ClientListener implements \Zend_EventManager_ListenerAggregate
{
private $event;
function __construct()
{
$this->event = new \Zend_EventManager_EventManager();
}
public function attach(\Zend_EventManager_EventCollection $events)
{
$Handler = new Handler();
$events->attach('tokenStorage', array($Handler, 'tokenAndDataStorage'), 100);
$events->attach('user.check', array($Handler, 'userCheck'), 100);
}
public function detach(\Zend_EventManager_EventCollection $events)
{
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Open\Listener;
use Open\Handler\OauthHandler;
class OauthListener implements \Zend_EventManager_ListenerAggregate
{
private $event;
function __construct()
{
$this->event = new \Zend_EventManager_EventManager();
}
public function attach(\Zend_EventManager_EventCollection $events)
{
$Handler = new OauthHandler();
$events->attach('submit.checkParam', array($Handler, 'checkParam'), 100);
}
public function detach(\Zend_EventManager_EventCollection $events)
{
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace Open\Listener;
use Open\Handler\OpenHandler as Handler;
class OpenListener implements \Zend_EventManager_ListenerAggregate
{
private $event;
function __construct()
{
$this->event = new \Zend_EventManager_EventManager();
}
public function attach(\Zend_EventManager_EventCollection $events)
{
$Handler = new Handler();
$events->attach('submit.checkParam', array($Handler, 'checkParam'), 100);
}
public function detach(\Zend_EventManager_EventCollection $events)
{
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace Open;
class OAuth2 extends \Zend_Controller_Plugin_Abstract
{
public $db;
public $auth = NULL;
public $user;
private $config;
public $table;
public function __construct($db = NULL,$auth = NULL){
if(empty($db))
{
$this->db = \Zend_Registry::get('db');
}else{
$this->db = $db;
}
$this->config = \Zend_Registry::get('config');
$this->table = new Table();
}
//用户使用谷歌账号登陆
public function googleClient()
{
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace Open\OAuth2;
use \Helpers\View as view;
use \Helpers\Table;
class Server extends \Zend_Controller_Plugin_Abstract
{
public $db;
public $auth = NULL;
public $user;
private $config;
public $table;
public function __construct($db = NULL,$auth = NULL){
if(empty($db))
{
$this->db = \Zend_Registry::get('db');
}else{
$this->db = $db;
}
$this->config = \Zend_Registry::get('config');
$this->table = new Table();
}
//根据ID或者Client_id获得app的信息
public function getClientInfo($id)
{
if(empty($id))
{
return "无效参数";
}
if(is_numeric($id))
{
$field = "id";
}else{
$field = "client_id";
}
$sql = "SELECT * FROM {$this->table->oauth_clients} WHERE $field=? LIMIT 1";
$sth = $this->db->prepare($sql);
$sth->execute(array($id));
$row = $sth->fetch();
return $row;
}
//验证App
public function clientCredentials($client_id,$client_secret)
{
$client = $this->getClientInfo($client_id);
if(empty($client['id']))
{
return "此应用ID未被证实";
}
if($client['status'] == -1)
{
return "此应用已关闭";
}
if($client['client_secret'] !== $client_secret)
{
return "Invalid client secret";
}
return true;
}
}

View File

@ -0,0 +1,126 @@
<?php
namespace Open;
use \stdClass;
class Source
{
private $website;
private $source;
private $target;
private $sourceType = array("westdc","heihedata","card");
public function __construct($website){
$this->source = new stdClass();
$this->target = new stdClass();
$this->website = $website;
$this->initSourceConfig();
$this->initTarget();
}
//获得当前绑定的站点
public function getCurrentSite(){
return $this->website;
}
//设置绑定的站点
public function setCurrentSite($website){
$this->website = $website;
$this->initSourceConfig();
}
private function initSourceConfig()
{
if(!in_array($this->website,$this->sourceType))
{
return false;
}
// Escience
// passport.escience.cn
$this->source->escience = new stdClass();
$this->source->escience->param = array(
"id" => "client_id",
"secret" => "client_secret",
"code_response" => "response_type",
"grant_type" => "grant_type",
"callback" => "redirect_uri",
"code"=>"code"
);
if($this->website == 'westdc'){
$this->source->escience->config = array(
'id' => '71852',
'secret' => 'ad7gd3jZgbzhQM6vIh9vPnQFZQoTGHZI',
'index' => 'http://westdc.westgis.ac.cn',
'callback' => 'http://westdc.westgis.ac.cn/account/callback/type/escience',
'other' => array(
'theme'=>'full'
)
);
}
if($this->website == 'heihedata'){
$this->source->escience->config = array(
'id' => '78969',
'secret' => 'iTGKdCkUPakA2hza2TJ4XZ4cnwlh8Hqz',
'index' => 'http://www.heihedata.org',
'callback' => 'http://www.heihedata.org/account/callback/type/escience',
'other' => array(
'theme'=>'full'
)
);
}
}
//获得一个源
public function getSource($type = "")
{
if(empty($type))
{
return $this->source;
}else{
if(isset($this->source->$type))
{
return $this->source->$type;
}else{
return false;
}
}
}
//Oauth2登录目标
private function initTarget(){
$this->target->escience = array(
'name' => '中国科技网通行证',
'code' => 'http://passport.escience.cn/oauth2/authorize',
'token' => 'https://passport.escience.cn/oauth2/token',
'code_response' => 'code',
'grant_type' => 'authorization_code',
);
}
//获得Oauth2登录模板
public function getTarget($type = "")
{
if(empty($type))
{
return $this->target;
}else{
if(isset($this->target->$type))
{
return $this->target->$type;
}else{
return false;
}
}
}
}

View File

@ -29,22 +29,9 @@ class Server extends \Zend_Controller_Plugin_Abstract
} }
} }
public function bootstrap() public function getCode()
{ {
$dsn = "pgsql:dbname={$this->config->db->params->dbname};host={$this->config->db->params->host}";
$storage = new \OAuth2\Storage\Pdo(array('dsn' => $dsn, 'username' => $this->config->db->params->username, 'password' => $this->config->db->params->password));
$server = new \OAuth2\Server($storage);
$server->addGrantType(new \OAuth2\GrantType\ClientCredentials($storage));
$server->addGrantType(new \OAuth2\GrantType\AuthorizationCode($storage));
//应用授权
//$server->handleTokenRequest(OAuth2\Request::createFromGlobals())->send();
return $server;
} }
} }