Auth.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. <?php
  2. namespace Easemob;
  3. use Easemob\Http\Http;
  4. use Easemob\Cache\Cache;
  5. use Easemob\Agora\ChatTokenBuilder2;
  6. use Easemob\Agora\AccessToken2;
  7. /**
  8. * 授权类
  9. * @final
  10. */
  11. final class Auth
  12. {
  13. private static $DNS_URL = 'https://rs.easemob.com';
  14. /**
  15. * @ignore
  16. * @var string $apiUri rest 域名
  17. */
  18. private $apiUri;
  19. /**
  20. * @ignore
  21. * @var string $orgName 企业唯一标识 org_name
  22. */
  23. private $orgName;
  24. /**
  25. * @ignore
  26. * @var string $appName 企业下 APP 唯一标识 app_name
  27. */
  28. private $appName;
  29. /**
  30. * @ignore
  31. * @var string $appKey APP 的唯一标识,规则是 ${org_name}#${app_name}
  32. */
  33. private $appKey;
  34. /**
  35. * @ignore
  36. * @var string $clientId App 的 client_id
  37. */
  38. private $clientId;
  39. /**
  40. * @ignore
  41. * @var string $clientSecret App 的 client_secret
  42. */
  43. private $clientSecret;
  44. /**
  45. * @ignore
  46. * @var string $easemobToken 环信 token
  47. */
  48. private $easemobToken;
  49. /**
  50. * @ignore
  51. * @var boolean $isAgora 是否以声网 token 初始化标识
  52. */
  53. private $isAgora;
  54. /**
  55. * @ignore
  56. * @var string $appID 声网 App ID
  57. */
  58. private $appID;
  59. /**
  60. * @ignore
  61. * @var string $appCertificate 声网 App 证书
  62. */
  63. private $appCertificate;
  64. /**
  65. * @ignore
  66. * @var int $expireTimeInSeconds 声网 token 有效期,单位(秒)
  67. */
  68. private $expireTimeInSeconds;
  69. /**
  70. * @ignore
  71. * @var string $uuid 环信用户 uuid
  72. */
  73. private $uuid;
  74. /**
  75. * @ignore
  76. * @var string $agoraToken2easemobToken 声网 token 置换的环信 token
  77. */
  78. private $agoraToken2easemobToken;
  79. /**
  80. * \~chinese
  81. * \brief 构造方法
  82. *
  83. * @param string $appKey APP 的唯一标识,规则是 ${org_name}#${app_name}
  84. * @param string $clientIdOrAppID 环信 App 的 client_id 或者声网 App ID,由 boolean $isAgora 决定
  85. * @param string $clientSecretOrAppCertificate 环信 App 的 client_secret 或者 声网 App 证书,由 boolean $isAgora 决定
  86. * @param int $expireTimeInSeconds token 有效期,单位(秒)
  87. * @param mixed $proxy 代理信息
  88. * @param boolean $isAgora 是否使用声网 token 初始化
  89. * @param string $uuid 环信用户 uuid
  90. *
  91. * \~english
  92. * \brief 构造方法
  93. *
  94. * @param string $appKey The unique identification of app. The rule is ${org_name}#${app_name}
  95. * @param string $clientIdOrAppID easemob client_id or Agora App ID,Determined by $isagora
  96. * @param string $clientSecretOrAppCertificate easemob client_secret or Agora AppCertificate,Determined by $isagora
  97. * @param int $expireTimeInSeconds Token validity, in seconds
  98. * @param mixed $proxy Agent information
  99. * @param boolean $isAgora Whether to use Agora token initialization
  100. * @param string $uuid easemob username
  101. */
  102. public function __construct(
  103. $appKey,
  104. $clientIdOrAppID,
  105. $clientSecretOrAppCertificate,
  106. $expireTimeInSeconds = 2592000,
  107. $isAgora = false,
  108. $uuid = ''
  109. )
  110. {
  111. if (strpos($appKey, '#') === false) {
  112. throw new \Exception('appKey 数据结构有误');
  113. }
  114. $temp = explode('#', $appKey);
  115. $this->orgName = $temp[0];
  116. $this->appName = $temp[1];
  117. $this->appKey = $appKey;
  118. $this->expireTimeInSeconds = (int)$expireTimeInSeconds > 0 ? (int)$expireTimeInSeconds : 2592000;
  119. $this->isAgora = $isAgora;
  120. $this->uuid = $uuid;
  121. // $this->getApiUri();
  122. if ($isAgora) {
  123. $this->appID = $clientIdOrAppID;
  124. $this->appCertificate = $clientSecretOrAppCertificate;
  125. // $this->getAgoraToken2easemobToken();
  126. } else {
  127. $this->clientId = $clientIdOrAppID;
  128. $this->clientSecret = $clientSecretOrAppCertificate;
  129. // $this->getEasemobToken();
  130. }
  131. }
  132. /// @cond
  133. /**
  134. * @ignore getter & setter
  135. */
  136. public function getBaseUri()
  137. {
  138. return $this->getApiUri() . '/' . $this->orgName . '/' . $this->appName;
  139. }
  140. /**
  141. * @ignore getter & setter
  142. */
  143. public function getOrgName()
  144. {
  145. return $this->orgName;
  146. }
  147. /**
  148. * @ignore getter & setter
  149. */
  150. public function getAppName()
  151. {
  152. return $this->appName;
  153. }
  154. /**
  155. * @ignore getter & setter
  156. */
  157. public function getAppKey()
  158. {
  159. return $this->appKey;
  160. }
  161. /**
  162. * @ignore getter & setter
  163. */
  164. public function getClientId()
  165. {
  166. return $this->clientId;
  167. }
  168. /**
  169. * @ignore getter & setter
  170. */
  171. public function getClientSecret()
  172. {
  173. return $this->clientSecret;
  174. }
  175. /**
  176. * @ignore getter & setter
  177. */
  178. public function getApiUri()
  179. {
  180. return $this->apiUri ? $this->apiUri : $this->getRemoteApiUri();
  181. }
  182. /**
  183. * @ignore getter & setter
  184. */
  185. public function setApiUri($apiUri)
  186. {
  187. $this->apiUri = $apiUri;
  188. }
  189. /**
  190. * @ignore 获取环信 token
  191. * @return string 环信 token
  192. * @example
  193. * <pre>
  194. * $auth->getEasemobToken();
  195. * </pre>
  196. */
  197. public function getEasemobToken()
  198. {
  199. $this->easemobToken = Cache::get($this->appKey . '_easemob_token');
  200. return $this->easemobToken ? $this->easemobToken : $this->getEasemobAccessToken();
  201. }
  202. /**
  203. * @ignore 获取声网 token
  204. * @param string 环信用户 uuid
  205. * @param int token 有效期
  206. * @return string 声网 token
  207. * @example
  208. * <pre>
  209. * $auth->getAgoraToken();
  210. * </pre>
  211. */
  212. public function getAgoraToken()
  213. {
  214. if ($this->isAgora) {
  215. $this->agoraToken = Cache::get($this->appKey . '_agora_token');
  216. if (!$this->agoraToken) {
  217. if ($this->uuid) {
  218. $this->agoraToken = ChatTokenBuilder2::buildUserToken($this->appID, $this->appCertificate, $this->uuid, $this->expireTimeInSeconds);
  219. } else {
  220. $this->agoraToken = ChatTokenBuilder2::buildAppToken($this->appID, $this->appCertificate, $this->expireTimeInSeconds);
  221. }
  222. Cache::set($this->appKey . '_agora_token', $this->agoraToken, $this->expireTimeInSeconds);
  223. }
  224. return $this->agoraToken;
  225. }
  226. return '';
  227. }
  228. /**
  229. * @ignore 获取声网 token 置换的环信 token
  230. * @return string 声网 token 置换的环信 token
  231. * @example
  232. * <pre>
  233. * $auth->getAgoraToken2easemobToken();
  234. * </pre>
  235. */
  236. public function getAgoraToken2easemobToken()
  237. {
  238. if ($this->isAgora) {
  239. $this->agoraToken2easemobToken = Cache::get($this->appKey . '_agora_2_easemob_token');
  240. if (!$this->agoraToken2easemobToken) {
  241. $agoraToken = $this->getAgoraToken();
  242. $this->agoraToken2easemobToken();
  243. }
  244. return $this->agoraToken2easemobToken;
  245. }
  246. return '';
  247. }
  248. /// @endcond
  249. /**
  250. * \~chinese
  251. * \brief
  252. * 获取用户 token
  253. *
  254. * @param string $username 环信 IM 用户名,或者 uuid
  255. * @param string $password 环信用户密码,传递时获取 Easemob userToken 否则获取 Agora userToken
  256. * @param int $expireInSeconds token 过期时间,单位:s
  257. * @param array $configuration privileges
  258. * @return array 用户 token 信息或者错误
  259. *
  260. * \~english
  261. * \brief
  262. * Get user token
  263. *
  264. * @param string $username easemob user name or uuid
  265. * @param string $password easemob user login password, obtain easemob usertoken when passing, otherwise obtain Agora usertoken
  266. * @param int $expireInSeconds Expiration time of token, unit: S
  267. * @param array $configuration privileges
  268. * @return array User token information or error
  269. */
  270. public function getUserToken($username, $password = null, $expireInSeconds = 3600, $configuration = null)
  271. {
  272. if ($password) {
  273. $body = array(
  274. 'grant_type' => 'password',
  275. 'username' => $username,
  276. 'password' => $password,
  277. );
  278. if ($expireInSeconds) {
  279. $expireInSeconds = (int)$expireInSeconds;
  280. if ($expireInSeconds) {
  281. $body['ttl'] = $expireInSeconds;
  282. }
  283. }
  284. $uri = $this->getBaseUri() . '/token';
  285. $resp = Http::post($uri, $body);
  286. if (!$resp->ok()) {
  287. return \Easemob\error($resp);
  288. }
  289. $data = $resp->data();
  290. return array(
  291. 'access_token' => $data['access_token'],
  292. 'expires_in' => $data['expires_in'],
  293. );
  294. } elseif ($this->isAgora) {
  295. if ($configuration) {
  296. $accessToken = new AccessToken2($this->appID, $this->appCertificate, $expireInSeconds);
  297. foreach ($configuration as $item) {
  298. $accessToken->addService($item);
  299. }
  300. $userToken = $accessToken->build();
  301. } else {
  302. $userToken = ChatTokenBuilder2::buildUserToken($this->appID, $this->appCertificate, $username, $expireInSeconds);
  303. }
  304. return array(
  305. 'access_token' => $userToken,
  306. 'expires_in' => $expireInSeconds ? $expireInSeconds : $this->expireTimeInSeconds,
  307. );
  308. }
  309. }
  310. /// @cond
  311. /**
  312. * @ignore 获取请求头
  313. * @return array 请求头
  314. */
  315. public function headers()
  316. {
  317. $res = $this->isAgora ? $this->getAgoraToken2easemobToken() : $this->getEasemobToken();
  318. if (!isset($res['code']) && is_string($res)) {
  319. return array(
  320. 'Authorization' => 'Bearer ' . $res,
  321. );
  322. }
  323. }
  324. /// @endcond
  325. /**
  326. * @ignore 获取 REST API 域名
  327. * @return string REST API 域名
  328. */
  329. private function getRemoteApiUri()
  330. {
  331. $uri = self::$DNS_URL . '/easemob/server.json?app_key=' . $this->appKey;
  332. $resp = Http::get($uri);
  333. if ($resp->ok()) {
  334. $data = $resp->data();
  335. $restDomains = array_values(array_filter($data['rest']['hosts'], function($item) {
  336. return $item['protocol'] === 'https';
  337. }));
  338. $this->apiUri = $restDomains[0]['protocol'] . '://' . $restDomains[0]['domain'];
  339. return $this->apiUri;
  340. }
  341. return '';
  342. }
  343. /**
  344. * @ignore 获取环信 token
  345. * @return string 环信 token
  346. */
  347. private function getEasemobAccessToken()
  348. {
  349. // 环信 token
  350. $uri = $this->getBaseUri() . '/token';
  351. $body = array(
  352. 'grant_type' => 'client_credentials',
  353. 'client_id' => $this->clientId,
  354. 'client_secret' => $this->clientSecret,
  355. 'ttl' => $this->expireTimeInSeconds,
  356. );
  357. $resp = Http::post($uri, $body);
  358. if (!$resp->ok()) {
  359. return \Easemob\error($resp);
  360. }
  361. $data = $resp->data();
  362. if ($data['access_token']) {
  363. Cache::set($this->appKey . '_easemob_token', $data['access_token'], $data['expires_in']/2);
  364. return $data['access_token'];
  365. }
  366. return '';
  367. }
  368. /**
  369. * @ignore 声网 token 置换环信 token
  370. * @param string 环信用户 uuid
  371. * @param int token 有效期
  372. */
  373. private function agoraToken2easemobToken()
  374. {
  375. $uri = 'http://a41.easemob.com/' . $this->orgName . '/' . $this->appName . '/token';
  376. $body = array(
  377. 'grant_type' => 'agora',
  378. );
  379. $headers = array(
  380. 'Authorization' => 'Bearer ' . $this->agoraToken,
  381. );
  382. $resp = Http::post($uri, $body, $headers);
  383. if (!$resp->ok()) {
  384. return \Easemob\error($resp);
  385. }
  386. $data = $resp->data();
  387. if ($data['access_token']) {
  388. $this->agoraToken2easemobToken = $data['access_token'];
  389. Cache::set($this->appKey . '_agora_2_easemob_token', $data['access_token'], 2592000);
  390. }
  391. }
  392. }