|
@@ -0,0 +1,220 @@
|
|
|
+<?php
|
|
|
+
|
|
|
+namespace App\Service;
|
|
|
+
|
|
|
+use Illuminate\Support\Facades\Redis;
|
|
|
+
|
|
|
+class DrbService extends Service
|
|
|
+{
|
|
|
+ const RedisKey = 'DRBACCESSTOKENKEY';
|
|
|
+
|
|
|
+ public function getAccessToken1($data)
|
|
|
+ {
|
|
|
+ $code = $data['code'] ?? ''; // URL上的授权码
|
|
|
+ if (! $code) return [false, '授权码不能为空'];
|
|
|
+
|
|
|
+ // Step 1: 获取 access_token(建议缓存到 redis,2小时有效)
|
|
|
+ $appKey = config('dingtalk.app_key');
|
|
|
+ $appSecret = config('dingtalk.app_secret');
|
|
|
+ // 请求体必须是 JSON
|
|
|
+ $postData = [
|
|
|
+ "appKey" => $appKey,
|
|
|
+ "appSecret" => $appSecret
|
|
|
+ ];
|
|
|
+ $tokenResp = $this->curlOpen('https://api.dingtalk.com/v1.0/oauth2/accessToken',[
|
|
|
+ 'post' => true,
|
|
|
+ 'request' => 'post',
|
|
|
+ 'isupfile' => false,
|
|
|
+ 'header' => ['Content-Type: application/json'],
|
|
|
+ 'post' => json_encode($postData)
|
|
|
+ ]);
|
|
|
+ $tokenResp = json_decode($tokenResp,true);
|
|
|
+
|
|
|
+ if (empty($tokenResp['accessToken'])) return [false, '获取 access_token 失败'];
|
|
|
+ $accessToken = $tokenResp['accessToken'];
|
|
|
+
|
|
|
+ // Step2: 用 code 获取用户信息
|
|
|
+ $userInfoResp = $this->curlOpen('https://oapi.dingtalk.com/topapi/v2/user/getuserinfo', [
|
|
|
+ 'post' => true,
|
|
|
+ 'request' => 'post',
|
|
|
+ 'isupfile' => false,
|
|
|
+ 'header' => ["x-acs-dingtalk-access-token: {$accessToken}", "Content-Type: application/json"],
|
|
|
+ 'post' => json_encode(['code' => $code])
|
|
|
+ ]);
|
|
|
+ $userInfoResp = json_decode($userInfoResp, true);dd($userInfoResp);
|
|
|
+ $userId = $userInfoResp['result']['userId'] ?? null;
|
|
|
+ if (!$userId) return ['error' => '获取用户信息失败或 code 已过期'];
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // 获取用户信息
|
|
|
+ $userInfoUrl = "https://oapi.dingtalk.com/topapi/v2/user/getuserinfo?access_token={$accessToken}";
|
|
|
+ $postData = [
|
|
|
+ 'code' => $code
|
|
|
+ ];
|
|
|
+ $tokenResp = $this->curlOpen($userInfoUrl,[
|
|
|
+ 'post' => true,
|
|
|
+ 'request' => 'post',
|
|
|
+ 'isupfile' => false,
|
|
|
+ 'header' => ['Content-Type: application/json'],
|
|
|
+ 'post' => json_encode($postData)
|
|
|
+ ]);
|
|
|
+ $tokenResp = json_decode($tokenResp,true);
|
|
|
+ dd($tokenResp,$userInfoUrl,$postData);
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ // Step 2: 用 code 换取用户信息
|
|
|
+ $url = "https://oapi.dingtalk.com/user/getuserinfo?access_token={$accessToken}&code={$code}";
|
|
|
+ $tokenResp = $this->curlOpen($url);
|
|
|
+ dd($tokenResp,$url);
|
|
|
+
|
|
|
+ if (isset($userResp['errcode']) && $userResp['errcode'] != 0) {
|
|
|
+ return response()->json(['error' => '获取用户失败', 'detail' => $userResp], 500);
|
|
|
+ }
|
|
|
+
|
|
|
+ // userResp 里有 userid
|
|
|
+ $dingUserId = $userResp['userid'];
|
|
|
+
|
|
|
+ // Step 3: 你自己系统里维护映射关系 (假设表 user_bindings 记录了 dingtalk_userid ↔ u8_username)
|
|
|
+ $u8User = \DB::table('user_bindings')->where('dingtalk_userid', $dingUserId)->first();
|
|
|
+
|
|
|
+ if (!$u8User) {
|
|
|
+ return response()->json(['error' => '该钉钉账号未绑定 U8 用户'], 403);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Step 4: 返回登录成功信息
|
|
|
+ return response()->json([
|
|
|
+ 'dingUserId' => $dingUserId,
|
|
|
+ 'u8User' => $u8User->u8_username,
|
|
|
+ 'message' => '登录成功'
|
|
|
+ ]);
|
|
|
+ }
|
|
|
+
|
|
|
+ public function getAccessToken()
|
|
|
+ {
|
|
|
+ $token = Redis::get(self::RedisKey);
|
|
|
+ if(! empty($token)) return [true, ['access_token' => $token]];
|
|
|
+
|
|
|
+ $appKey = config('dingtalk.app_key');
|
|
|
+ $appSecret = config('dingtalk.app_secret');
|
|
|
+ $url = "https://api.dingtalk.com/v1.0/oauth2/accessToken";
|
|
|
+ $resp = $this->curlOpen1($url, [
|
|
|
+ 'request' => 'post',
|
|
|
+ 'header' => ['Content-Type: application/json'],
|
|
|
+ 'json' => [
|
|
|
+ "appKey" => $appKey,
|
|
|
+ "appSecret" => $appSecret
|
|
|
+ ]
|
|
|
+ ]);
|
|
|
+ $res = json_decode($resp, true);
|
|
|
+ $accessToken = $res['accessToken'] ?? "";
|
|
|
+ $expires_in = $res['expires_in'] ?? 0;
|
|
|
+ if(empty($accessToken)) return [false, 'AccessToken获取失败'];
|
|
|
+ Redis::setex(self::RedisKey, $expires_in, $accessToken);
|
|
|
+
|
|
|
+ return [true, ['access_token' => $accessToken]];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据前端传来的免登 code 获取用户信息
|
|
|
+ * @param string $code 前端 dd.getAuthCode 获取的 code
|
|
|
+ * @return array [bool, data] bool 表示成功与否,data 成功返回用户信息,失败返回错误信息
|
|
|
+ */
|
|
|
+ public function getUserByCode(string $code)
|
|
|
+ {
|
|
|
+ if (empty($code)) {
|
|
|
+ return [false, 'code不能为空'];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 1. 获取 access_token
|
|
|
+ [$success, $tokenData] = $this->getAccessToken();
|
|
|
+ if (!$success) return [false, $tokenData]; // tokenData 是错误信息
|
|
|
+ $accessToken = $tokenData['access_token'];
|
|
|
+
|
|
|
+ // 2. 用 code 换取 userid
|
|
|
+ $url = "https://api.dingtalk.com/v1.0/user/getuserinfo";
|
|
|
+ $resp = $this->curlOpen1($url, [
|
|
|
+ 'request' => 'post',
|
|
|
+ 'header' => [
|
|
|
+ "Content-Type: application/json",
|
|
|
+ "x-acs-dingtalk-access-token: {$accessToken}"
|
|
|
+ ],
|
|
|
+ 'json' => [
|
|
|
+ "code" => $code
|
|
|
+ ]
|
|
|
+ ]);
|
|
|
+
|
|
|
+ $res = json_decode($resp, true);
|
|
|
+ $userid = $res['result']['userid'] ?? null;
|
|
|
+ if (!$userid) {
|
|
|
+ return [false, '获取userid失败:' . $res['errmsg']];
|
|
|
+ }
|
|
|
+
|
|
|
+ return [true, $res];
|
|
|
+
|
|
|
+// // 3. 根据 userid 获取用户详情
|
|
|
+// $urlDetail = "https://api.dingtalk.com/v1.0/user/get";
|
|
|
+// $respDetail = $this->curlOpen1($urlDetail, [
|
|
|
+// 'request' => 'post',
|
|
|
+// 'header' => [
|
|
|
+// "Content-Type: application/json",
|
|
|
+// "x-acs-dingtalk-access-token: {$accessToken}"
|
|
|
+// ],
|
|
|
+// 'json' => [
|
|
|
+// "userid" => $userid
|
|
|
+// ]
|
|
|
+// ]);
|
|
|
+//
|
|
|
+// $detail = json_decode($respDetail, true);
|
|
|
+// if (empty($detail['result'])) {
|
|
|
+// return [false, '获取用户详情失败:' . ($detail['msg'] ?? json_encode($detail))];
|
|
|
+// }
|
|
|
+
|
|
|
+ // 返回用户信息
|
|
|
+// return [true, $detail['result']];
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ protected function curlOpen1($url, $config = [])
|
|
|
+ {
|
|
|
+ $default = [
|
|
|
+ 'post' => false,
|
|
|
+ 'request' => 'get',
|
|
|
+ 'header' => [],
|
|
|
+ 'json' => null,
|
|
|
+ 'timeout' => 30
|
|
|
+ ];
|
|
|
+
|
|
|
+ $arr = array_merge($default, $config);
|
|
|
+
|
|
|
+ $ch = curl_init();
|
|
|
+ curl_setopt($ch, CURLOPT_URL, $url);
|
|
|
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
|
+ curl_setopt($ch, CURLOPT_TIMEOUT, $arr['timeout']);
|
|
|
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
|
|
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
|
|
+
|
|
|
+ if (!empty($arr['header'])) {
|
|
|
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $arr['header']);
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($arr['post'] || $arr['request'] !== 'get') {
|
|
|
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($arr['request']));
|
|
|
+ if ($arr['json'] !== null) {
|
|
|
+ curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($arr['json'], JSON_UNESCAPED_UNICODE));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ $result = curl_exec($ch);
|
|
|
+ if ($result === false) {
|
|
|
+ $err = curl_error($ch);
|
|
|
+ curl_close($ch);
|
|
|
+ return json_encode(['error' => $err]);
|
|
|
+ }
|
|
|
+
|
|
|
+ curl_close($ch);
|
|
|
+ return $result;
|
|
|
+ }
|
|
|
+
|
|
|
+}
|