No Description

AccessTokenService.php 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <?php
  2. namespace App\Service;
  3. use App\Log;
  4. use App\RedisModel;
  5. class AccessTokenService
  6. {
  7. const ACCESS_TOKEN_RDS = 'qyWechat::AccessTokenBySecret_';
  8. const ACCESS_TOKEN_REQUEST_LOCK = 'qyWechat::AccessTokenRequestLockRds_';
  9. /**
  10. * 获取代开发应用AccessToken
  11. * */
  12. public static function getAccessToken($corpid, $from='')
  13. {
  14. # 判断是否为待开发应用
  15. $accessTokenStr = RedisModel::get(AccessTokenService::ACCESS_TOKEN_RDS. '_' .$corpid);
  16. Log::logInfo('【'.$corpid.'】Redis取出的结果为'.$accessTokenStr, [], 'GetAccessTokenTrace');
  17. if(!empty($accessTokenStr)) {
  18. Log::logInfo('【'.$corpid.'】发现了结果,开始解析:'.$accessTokenStr, [], 'GetAccessTokenTrace');
  19. $accessTokenData = json_decode($accessTokenStr, true);
  20. $accessToken = isset($accessTokenData['access_token']) ?
  21. $accessTokenData['access_token'] : '';
  22. $expire = $accessTokenData['expire'];
  23. $updateTime = isset($accessTokenData['update_time']) ? $accessTokenData['update_time'] : 0;
  24. if($expire <= time() || empty($accessToken) || $updateTime < time()) {
  25. Log::logInfo('【'.$corpid.'】满足请求gettoken接口刷新access_token条件', [
  26. 'request_time' => date('Y-m-d H:i:s'),
  27. 'expire_time' => date('Y-m-d H:i:s', $expire),
  28. 'update_time' => date('Y-m-d H:i:s', $updateTime),
  29. 'access_token' => $accessToken
  30. ], 'GetAccessTokenTrace');
  31. self::refreshAccessToken($corpid, $accessToken, $from);
  32. }
  33. } else {
  34. $accessToken = '';
  35. Log::logInfo('【'.$corpid.'】没有找到AccessToken,开始生成', [], 'GetAccessTokenTrace');
  36. self::refreshAccessToken($corpid, $accessToken, $from);
  37. }
  38. Log::logInfo('【'.$corpid.'】本次返回的AccessToken为' . $accessToken, [], 'GetAccessTokenTrace');
  39. return $accessToken;
  40. }
  41. /**
  42. * 调用接口刷新AccessToken
  43. * @param string $corpid 企业ID
  44. * @param string $accessToken 当前缓存的access_token,更新成功后会返回新access_token
  45. * @param string $from 获取令牌的方法说明
  46. * @param int $retry 重试次数
  47. * */
  48. public static function refreshAccessToken($corpid,&$accessToken, $from='',$retry=0)
  49. {
  50. # 判断请求锁
  51. $lockJson = RedisModel::get(AccessTokenService::ACCESS_TOKEN_REQUEST_LOCK . $corpid);
  52. if(!empty($lockJson)) {
  53. $lockData = json_decode($lockJson, true);
  54. $lockStatus = $lockData['lock_status'];
  55. if($lockStatus) { // 请求锁开启
  56. $requestTime = $lockData['request_time'];
  57. if($requestTime > time()) { // 请求锁截止时间大于当前时间,则不执行刷新请求
  58. Log::logInfo('【'.$corpid.'】本次请求gettoken接口触发锁限制', [
  59. 'request_time' => date('Y-m-d H:i:s'),
  60. 'lock_request_time' => date('Y-m-d H:i:s', $requestTime),
  61. 'lock_status' => $lockStatus
  62. ], 'GetAccessTokenTrace');
  63. return false;
  64. }
  65. }
  66. }
  67. $corpInfo = config('qyWechat.corp_info');
  68. $secret = $corpInfo[$corpid] ?? null;
  69. Log::logInfo('【'.$corpid.'】这是我的secret'.$secret, [], 'GetAccessTokenTrace');
  70. $redisKey = AccessTokenService::ACCESS_TOKEN_RDS. '_' .$corpid;
  71. # 获取令牌API地址
  72. $apiRefreshTokenUrl = config('qyWechat.get_access_token');
  73. $apiRefreshTokenUrl .= $corpid .'&corpsecret='.$secret;
  74. Log::logInfo('【'.$corpid.'】获取AccessToken链接:'.$apiRefreshTokenUrl, [], 'GetAccessTokenTrace');
  75. $response = HttpService::httpGet($apiRefreshTokenUrl);
  76. Log::logInfo('【'.$corpid.'】请求来源信息:'. $from, [
  77. 'response' => $response
  78. ], 'RequestAccessTokenFrom');
  79. $responseData = json_decode($response, true);
  80. Log::logInfo('【'.$corpid.'】这是我的请求结果', ['response' => $responseData], 'GetAccessTokenTrace');
  81. if(empty($responseData) || (isset($responseData['errcode']) && $responseData['errcode'])) {
  82. $errCode = isset($responseData['errcode']) ? $responseData['errcode'] : '';
  83. if($errCode == 45009) { // 提示Api请求超限,设置请求锁
  84. AccessTokenService::setRequestLock($corpid, time() + 6*60, 1);
  85. }
  86. Log::logInfo('【'.$corpid.'】获取失败了……', $responseData, 'GetAccessTokenTrace');
  87. Log::logError('【'.$corpid.'】第三方平台令牌获取API请求响应结果异常', $responseData, 'RefreshAccessToken');
  88. return false;
  89. } else {
  90. Log::logInfo('【'.$corpid.'】获取令牌成功', $responseData, 'GetAccessTokenTrace');
  91. Log::logInfo('【'.$corpid.'】第三方平台令牌获取API请求响应成功', $responseData, 'RefreshAccessTokenSuccess');
  92. }
  93. $accessToken = $responseData['access_token'];
  94. $saveData = [
  95. 'access_token' => $accessToken,
  96. 'expire' => $responseData['expires_in'] + time(),
  97. 'update_time' => time() + 3600
  98. ];
  99. # 解除AccessToken请求锁
  100. AccessTokenService::setRequestLock($corpid, time(), 0);
  101. # 将accessToken存入Redis
  102. RedisModel::set($redisKey, json_encode($saveData));
  103. RedisModel::expire($redisKey, 7200);
  104. Log::logError('Redis KEY值为:', [
  105. 'key' => $redisKey,
  106. 'value' => $accessToken,
  107. 'corpid' => $corpid
  108. ], 'refreshAccessTokenSave');
  109. return 0;
  110. }
  111. /**
  112. * 设置AccessToken请求锁
  113. * @param $corpid string 企业id
  114. * @param $requestTime integer 下次允许请求刷新令牌的时间戳
  115. * @param $lockStatus integer 锁状态 0关闭 1打开
  116. * */
  117. public static function setRequestLock($corpid, $requestTime, $lockStatus)
  118. {
  119. $lockInfo = [
  120. 'request_time' => $requestTime,
  121. 'lock_status' => $lockStatus
  122. ];
  123. RedisModel::set(AccessTokenService::ACCESS_TOKEN_REQUEST_LOCK . $corpid, json_encode($lockInfo));
  124. }
  125. }