QQProvider.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. <?php
  2. /*
  3. * This file is part of the overtrue/socialite.
  4. *
  5. * (c) overtrue <i@overtrue.me>
  6. *
  7. * This source file is subject to the MIT license that is bundled
  8. * with this source code in the file LICENSE.
  9. */
  10. namespace Overtrue\Socialite\Providers;
  11. use Overtrue\Socialite\AccessTokenInterface;
  12. use Overtrue\Socialite\ProviderInterface;
  13. use Overtrue\Socialite\User;
  14. /**
  15. * Class QQProvider.
  16. *
  17. * @see http://wiki.connect.qq.com/oauth2-0%E7%AE%80%E4%BB%8B [QQ - OAuth 2.0 登录QQ]
  18. */
  19. class QQProvider extends AbstractProvider implements ProviderInterface
  20. {
  21. /**
  22. * The base url of QQ API.
  23. *
  24. * @var string
  25. */
  26. protected $baseUrl = 'https://graph.qq.com';
  27. /**
  28. * User openid.
  29. *
  30. * @var string
  31. */
  32. protected $openId;
  33. /**
  34. * get token(openid) with unionid.
  35. *
  36. * @var bool
  37. */
  38. protected $withUnionId = false;
  39. /**
  40. * User unionid.
  41. *
  42. * @var string
  43. */
  44. protected $unionId;
  45. /**
  46. * The scopes being requested.
  47. *
  48. * @var array
  49. */
  50. protected $scopes = ['get_user_info'];
  51. /**
  52. * The uid of user authorized.
  53. *
  54. * @var int
  55. */
  56. protected $uid;
  57. /**
  58. * Get the authentication URL for the provider.
  59. *
  60. * @param string $state
  61. *
  62. * @return string
  63. */
  64. protected function getAuthUrl($state)
  65. {
  66. return $this->buildAuthUrlFromBase($this->baseUrl.'/oauth2.0/authorize', $state);
  67. }
  68. /**
  69. * Get the token URL for the provider.
  70. *
  71. * @return string
  72. */
  73. protected function getTokenUrl()
  74. {
  75. return $this->baseUrl.'/oauth2.0/token';
  76. }
  77. /**
  78. * Get the Post fields for the token request.
  79. *
  80. * @param string $code
  81. *
  82. * @return array
  83. */
  84. protected function getTokenFields($code)
  85. {
  86. return parent::getTokenFields($code) + ['grant_type' => 'authorization_code'];
  87. }
  88. /**
  89. * Get the access token for the given code.
  90. *
  91. * @param string $code
  92. *
  93. * @return \Overtrue\Socialite\AccessToken
  94. */
  95. public function getAccessToken($code)
  96. {
  97. $response = $this->getHttpClient()->get($this->getTokenUrl(), [
  98. 'query' => $this->getTokenFields($code),
  99. ]);
  100. return $this->parseAccessToken($response->getBody()->getContents());
  101. }
  102. /**
  103. * Get the access token from the token response body.
  104. *
  105. * @param string $body
  106. *
  107. * @return \Overtrue\Socialite\AccessToken
  108. */
  109. public function parseAccessToken($body)
  110. {
  111. parse_str($body, $token);
  112. return parent::parseAccessToken($token);
  113. }
  114. /**
  115. * @return self
  116. */
  117. public function withUnionId()
  118. {
  119. $this->withUnionId = true;
  120. return $this;
  121. }
  122. /**
  123. * Get the raw user for the given access token.
  124. *
  125. * @param \Overtrue\Socialite\AccessTokenInterface $token
  126. *
  127. * @return array
  128. */
  129. protected function getUserByToken(AccessTokenInterface $token)
  130. {
  131. $url = $this->baseUrl.'/oauth2.0/me?access_token='.$token->getToken();
  132. $this->withUnionId && $url .= '&unionid=1';
  133. $response = $this->getHttpClient()->get($url);
  134. $me = json_decode($this->removeCallback($response->getBody()->getContents()), true);
  135. $this->openId = $me['openid'];
  136. $this->unionId = isset($me['unionid']) ? $me['unionid'] : '';
  137. $queries = [
  138. 'access_token' => $token->getToken(),
  139. 'openid' => $this->openId,
  140. 'oauth_consumer_key' => $this->clientId,
  141. ];
  142. $response = $this->getHttpClient()->get($this->baseUrl.'/user/get_user_info?'.http_build_query($queries));
  143. return json_decode($this->removeCallback($response->getBody()->getContents()), true);
  144. }
  145. /**
  146. * Map the raw user array to a Socialite User instance.
  147. *
  148. * @param array $user
  149. *
  150. * @return \Overtrue\Socialite\User
  151. */
  152. protected function mapUserToObject(array $user)
  153. {
  154. return new User([
  155. 'id' => $this->openId,
  156. 'unionid' => $this->unionId,
  157. 'nickname' => $this->arrayItem($user, 'nickname'),
  158. 'name' => $this->arrayItem($user, 'nickname'),
  159. 'email' => $this->arrayItem($user, 'email'),
  160. 'avatar' => $this->arrayItem($user, 'figureurl_qq_2'),
  161. ]);
  162. }
  163. /**
  164. * Remove the fucking callback parentheses.
  165. *
  166. * @param string $response
  167. *
  168. * @return string
  169. */
  170. protected function removeCallback($response)
  171. {
  172. if (strpos($response, 'callback') !== false) {
  173. $lpos = strpos($response, '(');
  174. $rpos = strrpos($response, ')');
  175. $response = substr($response, $lpos + 1, $rpos - $lpos - 1);
  176. }
  177. return $response;
  178. }
  179. }