DrbService.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. <?php
  2. namespace App\Service;
  3. use Illuminate\Support\Facades\Redis;
  4. class DrbService extends Service
  5. {
  6. const RedisKey = 'DRBACCESSTOKENKEY';
  7. public function getAccessToken1($data)
  8. {
  9. $code = $data['code'] ?? ''; // URL上的授权码
  10. if (! $code) return [false, '授权码不能为空'];
  11. // Step 1: 获取 access_token(建议缓存到 redis,2小时有效)
  12. $appKey = config('dingtalk.app_key');
  13. $appSecret = config('dingtalk.app_secret');
  14. // 请求体必须是 JSON
  15. $postData = [
  16. "appKey" => $appKey,
  17. "appSecret" => $appSecret
  18. ];
  19. $tokenResp = $this->curlOpen('https://api.dingtalk.com/v1.0/oauth2/accessToken',[
  20. 'post' => true,
  21. 'request' => 'post',
  22. 'isupfile' => false,
  23. 'header' => ['Content-Type: application/json'],
  24. 'post' => json_encode($postData)
  25. ]);
  26. $tokenResp = json_decode($tokenResp,true);
  27. if (empty($tokenResp['accessToken'])) return [false, '获取 access_token 失败'];
  28. $accessToken = $tokenResp['accessToken'];
  29. // Step2: 用 code 获取用户信息
  30. $userInfoResp = $this->curlOpen('https://oapi.dingtalk.com/topapi/v2/user/getuserinfo', [
  31. 'post' => true,
  32. 'request' => 'post',
  33. 'isupfile' => false,
  34. 'header' => ["x-acs-dingtalk-access-token: {$accessToken}", "Content-Type: application/json"],
  35. 'post' => json_encode(['code' => $code])
  36. ]);
  37. $userInfoResp = json_decode($userInfoResp, true);dd($userInfoResp);
  38. $userId = $userInfoResp['result']['userId'] ?? null;
  39. if (!$userId) return ['error' => '获取用户信息失败或 code 已过期'];
  40. // 获取用户信息
  41. $userInfoUrl = "https://oapi.dingtalk.com/topapi/v2/user/getuserinfo?access_token={$accessToken}";
  42. $postData = [
  43. 'code' => $code
  44. ];
  45. $tokenResp = $this->curlOpen($userInfoUrl,[
  46. 'post' => true,
  47. 'request' => 'post',
  48. 'isupfile' => false,
  49. 'header' => ['Content-Type: application/json'],
  50. 'post' => json_encode($postData)
  51. ]);
  52. $tokenResp = json_decode($tokenResp,true);
  53. dd($tokenResp,$userInfoUrl,$postData);
  54. // Step 2: 用 code 换取用户信息
  55. $url = "https://oapi.dingtalk.com/user/getuserinfo?access_token={$accessToken}&code={$code}";
  56. $tokenResp = $this->curlOpen($url);
  57. dd($tokenResp,$url);
  58. if (isset($userResp['errcode']) && $userResp['errcode'] != 0) {
  59. return response()->json(['error' => '获取用户失败', 'detail' => $userResp], 500);
  60. }
  61. // userResp 里有 userid
  62. $dingUserId = $userResp['userid'];
  63. // Step 3: 你自己系统里维护映射关系 (假设表 user_bindings 记录了 dingtalk_userid ↔ u8_username)
  64. $u8User = \DB::table('user_bindings')->where('dingtalk_userid', $dingUserId)->first();
  65. if (!$u8User) {
  66. return response()->json(['error' => '该钉钉账号未绑定 U8 用户'], 403);
  67. }
  68. // Step 4: 返回登录成功信息
  69. return response()->json([
  70. 'dingUserId' => $dingUserId,
  71. 'u8User' => $u8User->u8_username,
  72. 'message' => '登录成功'
  73. ]);
  74. }
  75. public function getAccessToken()
  76. {
  77. $token = Redis::get(self::RedisKey);
  78. if(! empty($token)) return [true, ['access_token' => $token]];
  79. $appKey = config('dingtalk.app_key');
  80. $appSecret = config('dingtalk.app_secret');
  81. $url = "https://api.dingtalk.com/v1.0/oauth2/accessToken";
  82. $resp = $this->curlOpen1($url, [
  83. 'request' => 'post',
  84. 'header' => ['Content-Type: application/json'],
  85. 'json' => [
  86. "appKey" => $appKey,
  87. "appSecret" => $appSecret
  88. ]
  89. ]);
  90. $res = json_decode($resp, true);
  91. $accessToken = $res['accessToken'] ?? "";
  92. $expires_in = $res['expires_in'] ?? 0;
  93. if(empty($accessToken)) return [false, 'AccessToken获取失败'];
  94. Redis::setex(self::RedisKey, $expires_in, $accessToken);
  95. return [true, ['access_token' => $accessToken]];
  96. }
  97. /**
  98. * 根据前端传来的免登 code 获取用户信息
  99. * @param string $code 前端 dd.getAuthCode 获取的 code
  100. * @return array [bool, data] bool 表示成功与否,data 成功返回用户信息,失败返回错误信息
  101. */
  102. public function getUserByCode(string $code)
  103. {
  104. if (empty($code)) return [false, '钉钉授权code不能为空'];
  105. // 1. 获取 access_token
  106. [$success, $tokenData] = $this->getAccessToken();
  107. if (! $success) return [false, $tokenData]; // tokenData 是错误信息
  108. $accessToken = $tokenData['access_token'];
  109. // 2. 用 code 换取用户信息(v2 接口)
  110. $url = "https://oapi.dingtalk.com/topapi/v2/user/getuserinfo?access_token={$accessToken}";
  111. $resp = $this->curlOpen1($url, [
  112. 'request' => 'post',
  113. 'header' => [
  114. "Content-Type: application/json",
  115. ],
  116. 'json' => [
  117. "code" => $code
  118. ]
  119. ]);
  120. $res = json_decode($resp, true);
  121. if (!isset($res['errcode'])) {
  122. return [false, '接口返回异常: ' . $resp];
  123. }
  124. if ($res['errcode'] !== 0) {
  125. return [false, '获取用户信息失败: ' . $res['errmsg']];
  126. }
  127. // v2 接口返回的是 result.user_id
  128. $userid = $res['result']['user_id'] ?? null;
  129. if (!$userid) {
  130. return [false, '获取userid失败'];
  131. }
  132. return [true, $res];
  133. }
  134. protected function curlOpen1($url, $config = [])
  135. {
  136. $default = [
  137. 'post' => false,
  138. 'request' => 'get',
  139. 'header' => [],
  140. 'json' => null,
  141. 'timeout' => 30
  142. ];
  143. $arr = array_merge($default, $config);
  144. $ch = curl_init();
  145. curl_setopt($ch, CURLOPT_URL, $url);
  146. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  147. curl_setopt($ch, CURLOPT_TIMEOUT, $arr['timeout']);
  148. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  149. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  150. if (!empty($arr['header'])) {
  151. curl_setopt($ch, CURLOPT_HTTPHEADER, $arr['header']);
  152. }
  153. if ($arr['post'] || $arr['request'] !== 'get') {
  154. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($arr['request']));
  155. if ($arr['json'] !== null) {
  156. curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($arr['json'], JSON_UNESCAPED_UNICODE));
  157. }
  158. }
  159. $result = curl_exec($ch);
  160. if ($result === false) {
  161. $err = curl_error($ch);
  162. curl_close($ch);
  163. return json_encode(['error' => $err]);
  164. }
  165. curl_close($ch);
  166. return $result;
  167. }
  168. }