PageRenderTime 110ms CodeModel.GetById 32ms RepoModel.GetById 2ms app.codeStats 0ms

/library/OpenApi/OAuth/OAuth.php

https://github.com/polokk/tudu-web-1
PHP | 330 lines | 178 code | 49 blank | 103 comment | 23 complexity | a13d99a5f915d347de95a4128444b54f MD5 | raw file
  1. <?php
  2. /**
  3. * Tudu OpenApi
  4. *
  5. * LICENSE
  6. *
  7. * @category OpenApi
  8. * @package OpenApi_OAuth
  9. * @copyright Copyright (c) 2009-2010 Shanghai Best Oray Information S&T CO., Ltd.
  10. * @link http://www.oray.com/
  11. * @version $Id$
  12. */
  13. /**
  14. * @category OpenApi
  15. * @package OpenApi_OAuth
  16. * @copyright Copyright (c) 2009-2010 Shanghai Best Oray Information S&T CO., Ltd.
  17. */
  18. class OpenApi_OAuth_OAuth
  19. {
  20. /**
  21. * 设置项目
  22. *
  23. * @var string
  24. */
  25. const STORAGE = 'storageType'; // 存储类型
  26. const ACCESS_TOKEN_EXPIRES = 'accessTokenExpires'; // 访问令牌过期时间
  27. const REFRESH_TOKEN_EXPIRES = 'refreshTokenExpires';
  28. const SUPPORT_REFRESH_TOKEN = 'supportRefreshToken'; // 是否实现刷新令牌
  29. const TOKEN_TYPE = 'tokenType';
  30. /**
  31. * 获取访问令牌方式类型
  32. *
  33. * @var string
  34. */
  35. const GRANT_TYPE_AUTH_CODE = 'authorization_code';
  36. const GRANT_TYPE_IMPLICIT = 'token';
  37. const GRANT_TYPE_USER_CREDENTIALS = 'password';
  38. const GRANT_TYPE_CLIENT_CREDENTIALS = 'client_credentials';
  39. const GRANT_TYPE_REFRESH_TOKEN = 'refresh_token';
  40. const GRANT_TYPE_EXTENSIONS = 'extensions';
  41. /**
  42. * 参数名称
  43. *
  44. * @var string
  45. */
  46. const PARAM_CLIENT_ID = 'client_id';
  47. const PARAM_CLIENT_SECRET = 'client_secret';
  48. const PARAM_REDIRECT_URI = 'redirect_uri';
  49. const PARAM_STATE = 'state';
  50. const PARAM_SCOPE = 'scope';
  51. const PARAM_GRANT_TYPE = 'grant_type';
  52. const PARAM_CODE = 'code';
  53. const PARAM_USERNAME = 'username';
  54. const PARAM_USER_ID = 'user_id';
  55. const PARAM_PASSWORD = 'password';
  56. const PARAM_REFRESH_TOKEN = 'refresh_token';
  57. const PARAM_ACCESS_TOKEN = 'access_token';
  58. const PARAM_EXPIRES = 'expires_in';
  59. /**
  60. * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-20#section-7.1
  61. *
  62. * @var string
  63. */
  64. const TOKEN_TYPE_BEARER = 'bearer';
  65. const TOKEN_TYPE_MAC = 'mac';
  66. /**
  67. *
  68. * @var string
  69. */
  70. const REG_GRANT_TYPE = '#^(authorization_code|token|password|client_credentials|refresh_token|http://.*)$#';
  71. /**
  72. *
  73. * @var string
  74. */
  75. const ERROR_INTERNAL_EXCEPTION = 'internal_exception';
  76. const ERROR_INVALID_REQUEST = 'invalid_request';
  77. const ERROR_INVALID_ACCESSTOKEN = 'invalid_access_token';
  78. const ERROR_ACCESSTOKEN_EXPIRED = 'access_token_expired';
  79. /**
  80. *
  81. * @var array
  82. */
  83. protected $_config = array(
  84. self::STORAGE => null,
  85. self::ACCESS_TOKEN_EXPIRES => 86400,
  86. self::REFRESH_TOKEN_EXPIRES => 259200,
  87. self::SUPPORT_REFRESH_TOKEN => true,
  88. self::TOKEN_TYPE => self::TOKEN_TYPE_BEARER
  89. );
  90. /**
  91. *
  92. * @var array
  93. */
  94. protected $_grantClasses = array(
  95. self::GRANT_TYPE_AUTH_CODE => 'OpenApi_OAuth_Grant_AuthCode',
  96. self::GRANT_TYPE_USER_CREDENTIALS => '',
  97. self::GRANT_TYPE_REFRESH_TOKEN => 'OpenApi_OAuth_Grant_RefreshToken'
  98. );
  99. /**
  100. *
  101. * @var OpenApi_OAuth_Storage_Interface
  102. */
  103. protected $_storage;
  104. /**
  105. * Constructor
  106. *
  107. * @param Zend_Config | array $config
  108. */
  109. public function __construct($config = null)
  110. {
  111. if ($config && $config instanceof Zend_Config) {
  112. $config = $config->toArray();
  113. }
  114. if (null !== $config && !is_array($config)) {
  115. require_once 'OpenApi/OAuth/Exception.php';
  116. throw new OpenApi_OAuth_Exception("Invalid config parameter for constructor of OAuth", self::ERROR_INTERNAL_EXCEPTION);
  117. }
  118. if (isset($config[self::STORAGE])
  119. && $config[self::STORAGE] instanceof OpenApi_OAuth_Storage_Interface)
  120. {
  121. $this->_storage = $config[self::STORAGE];
  122. }
  123. $this->_config = array_merge($this->_config, $config);
  124. }
  125. /**
  126. *
  127. * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-20#section-4
  128. * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-21#section-10.6
  129. * @see http://tools.ietf.org/html/draft-ietf-oauth-v2-21#section-4.1.3
  130. *
  131. * @param array $inputDate
  132. * @param array $authHeaders
  133. * @throws OpenApi_OAuth_Exception
  134. */
  135. public function grantAccessToken(array $inputData, array $authHeaders = null)
  136. {
  137. $filters = array(
  138. self::PARAM_GRANT_TYPE => array("filter" => FILTER_VALIDATE_REGEXP, "options" => array("regexp" => self::REG_GRANT_TYPE), "flags" => FILTER_REQUIRE_SCALAR),
  139. self::PARAM_SCOPE => array("flags" => FILTER_REQUIRE_SCALAR),
  140. self::PARAM_CODE => array("flags" => FILTER_REQUIRE_SCALAR),
  141. self::PARAM_REDIRECT_URI => array("filter" => FILTER_SANITIZE_URL),
  142. self::PARAM_USERNAME => array("flags" => FILTER_REQUIRE_SCALAR),
  143. self::PARAM_PASSWORD => array("flags" => FILTER_REQUIRE_SCALAR),
  144. self::PARAM_REFRESH_TOKEN => array("flags" => FILTER_REQUIRE_SCALAR),
  145. );
  146. if (empty($inputData)) {
  147. require_once 'OpenApi/OAuth/Exception.php';
  148. throw new OpenApi_OAuth_Exception(self::ERROR_INVALID_REQUEST);
  149. }
  150. $input = filter_var_array($inputData, $filters);
  151. if (empty($input[self::PARAM_GRANT_TYPE])) {
  152. require_once 'OpenApi/OAuth/Exception.php';
  153. throw new OpenApi_OAuth_Exception('Invalid parameter "grant_type"', self::ERROR_INVALID_REQUEST);
  154. }
  155. $grant = $this->getGrantObject($input[self::PARAM_GRANT_TYPE]);
  156. if (!$grant instanceof OpenApi_OAuth_Grant_Abstract) {
  157. require_once 'OpenApi/OAuth/Exception.php';
  158. throw new OpenApi_OAuth_Exception('Grant class must extends from class "OpenApi_OAuth_Grant_Abstract"');
  159. }
  160. $data = $grant->grant($inputData);
  161. $data[self::PARAM_CLIENT_ID] = $inputData[self::PARAM_CLIENT_ID];
  162. return $this->createAccessToken($data);
  163. }
  164. /**
  165. * 设置验证模式对象类
  166. *
  167. * @param string $grantType
  168. * @param string $className
  169. * @return OpenApi_OAuth_OAuth
  170. */
  171. public function setGrantClass($grantType, $className)
  172. {
  173. if (empty($className)) {
  174. require_once 'OpenApi/OAuth/Exception.php';
  175. throw new OpenApi_OAuth_Exception("Invalid classname for grant type");
  176. }
  177. $this->_grantClasses[$grantType] = $className;
  178. }
  179. /**
  180. *
  181. * @param string $grantType
  182. */
  183. public function getGrantObject($grantType)
  184. {
  185. require_once 'Zend/Loader.php';
  186. Zend_Loader::loadClass($this->_grantClasses[$grantType]);
  187. return new $this->_grantClasses[$grantType]($this);
  188. }
  189. /**
  190. *
  191. */
  192. public function createAccessToken(array $params)
  193. {
  194. $accessToken = $this->_getToken();
  195. $ret = array(
  196. 'access_token' => $accessToken,
  197. 'expires_in' => $this->_config[self::ACCESS_TOKEN_EXPIRES],
  198. 'token_type' => $this->_config[self::TOKEN_TYPE],
  199. 'scope' => $params[self::PARAM_SCOPE]
  200. );
  201. $token = array(
  202. self::PARAM_CLIENT_ID => $params[self::PARAM_CLIENT_ID],
  203. self::PARAM_USER_ID => $params[self::PARAM_USER_ID],
  204. self::PARAM_EXPIRES => time() + $this->_config[self::ACCESS_TOKEN_EXPIRES],
  205. self::PARAM_SCOPE => $params[self::PARAM_SCOPE]
  206. );
  207. $token = array_merge($params, $token);
  208. $this->getStorage()->setAccessToken($accessToken, $token);
  209. $a = $this->getStorage()->getAccessToken($accessToken);
  210. if ($this->_config[self::SUPPORT_REFRESH_TOKEN]) {
  211. $refreshToken = $this->_getToken();
  212. $ret['refresh_token'] = $refreshToken;
  213. $token[self::PARAM_EXPIRES] = time() + $this->_config[self::REFRESH_TOKEN_EXPIRES];
  214. $this->getStorage()->setRefreshToken($refreshToken, $token);
  215. }
  216. return $ret;
  217. }
  218. /**
  219. * 销毁指定的访问令牌
  220. *
  221. * @param string $accessToken
  222. */
  223. public function destroyAccessToken($accessToken)
  224. {
  225. $storage = $this->getStorage();
  226. $token = $storage->getAccessToken($accessToken);
  227. if (null === $token) {
  228. return ;
  229. }
  230. if (!empty($token[self::PARAM_REFRESH_TOKEN])) {
  231. $storage->unsetRefreshToken($token[self::PARAM_REFRESH_TOKEN]);
  232. }
  233. $storage->unsetAccessToken($accessToken);
  234. }
  235. /**
  236. *
  237. * @param string $accessToken
  238. * @param string $scope
  239. */
  240. public function verifyAccessToken($accessToken, $scope = null)
  241. {
  242. $token = $this->getStorage()->getAccessToken($accessToken);
  243. if (empty($token)) {
  244. require_once 'OpenApi/OAuth/Exception.php';
  245. throw new OpenApi_OAuth_Exception("Invalid access token provided", self::ERROR_INVALID_ACCESSTOKEN);
  246. }
  247. if (empty($token[self::PARAM_EXPIRES]) || empty($token[self::PARAM_CLIENT_ID])) {
  248. require_once 'OpenApi/OAuth/Exception.php';
  249. throw new OpenApi_OAuth_Exception("Invalid access token provided", self::ERROR_INVALID_ACCESSTOKEN);
  250. }
  251. if ($token[self::PARAM_EXPIRES] < time()) {
  252. require_once 'OpenApi/OAuth/Exception.php';
  253. throw new OpenApi_OAuth_Exception("Invalid access token provided", self::ERROR_ACCESSTOKEN_EXPIRED);
  254. }
  255. // 授权范围,未实现
  256. if (null != $scope) {
  257. }
  258. return $token;
  259. }
  260. /**
  261. *
  262. * 获取保存对象
  263. */
  264. public function getStorage()
  265. {
  266. return $this->_storage;
  267. }
  268. /**
  269. * 生成新的令牌字符串
  270. */
  271. protected function _getToken()
  272. {
  273. $tokenLen = 40;
  274. if (file_exists('/dev/urandom')) { // Get 100 bytes of random data
  275. $randomData = file_get_contents('/dev/urandom', false, null, 0, 100) . uniqid(mt_rand(), true);
  276. } else {
  277. $randomData = mt_rand() . mt_rand() . mt_rand() . mt_rand() . microtime(true) . uniqid(mt_rand(), true);
  278. }
  279. return substr(hash('sha512', $randomData), 0, $tokenLen);
  280. }
  281. }