123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- <?php
- namespace App\Service;
- use App\Log;
- use App\RedisModel;
- class AccessTokenService
- {
- const ACCESS_TOKEN_RDS = 'qyWechat::AccessTokenBySecret_';
- const ACCESS_TOKEN_REQUEST_LOCK = 'qyWechat::AccessTokenRequestLockRds_';
- /**
- * 获取代开发应用AccessToken
- * */
- public static function getAccessToken($corpid, $from='')
- {
- # 判断是否为待开发应用
- $accessTokenStr = RedisModel::get(AccessTokenService::ACCESS_TOKEN_RDS. '_' .$corpid);
- Log::logInfo('【'.$corpid.'】Redis取出的结果为'.$accessTokenStr, [], 'GetAccessTokenTrace');
- if(!empty($accessTokenStr)) {
- Log::logInfo('【'.$corpid.'】发现了结果,开始解析:'.$accessTokenStr, [], 'GetAccessTokenTrace');
- $accessTokenData = json_decode($accessTokenStr, true);
- $accessToken = isset($accessTokenData['access_token']) ?
- $accessTokenData['access_token'] : '';
- $expire = $accessTokenData['expire'];
- $updateTime = isset($accessTokenData['update_time']) ? $accessTokenData['update_time'] : 0;
- if($expire <= time() || empty($accessToken) || $updateTime < time()) {
- Log::logInfo('【'.$corpid.'】满足请求gettoken接口刷新access_token条件', [
- 'request_time' => date('Y-m-d H:i:s'),
- 'expire_time' => date('Y-m-d H:i:s', $expire),
- 'update_time' => date('Y-m-d H:i:s', $updateTime),
- 'access_token' => $accessToken
- ], 'GetAccessTokenTrace');
- self::refreshAccessToken($corpid, $accessToken, $from);
- }
- } else {
- $accessToken = '';
- Log::logInfo('【'.$corpid.'】没有找到AccessToken,开始生成', [], 'GetAccessTokenTrace');
- self::refreshAccessToken($corpid, $accessToken, $from);
- }
- Log::logInfo('【'.$corpid.'】本次返回的AccessToken为' . $accessToken, [], 'GetAccessTokenTrace');
- return $accessToken;
- }
- /**
- * 调用接口刷新AccessToken
- * @param string $corpid 企业ID
- * @param string $accessToken 当前缓存的access_token,更新成功后会返回新access_token
- * @param string $from 获取令牌的方法说明
- * @param int $retry 重试次数
- * */
- public static function refreshAccessToken($corpid,&$accessToken, $from='',$retry=0)
- {
- # 判断请求锁
- $lockJson = RedisModel::get(AccessTokenService::ACCESS_TOKEN_REQUEST_LOCK . $corpid);
- if(!empty($lockJson)) {
- $lockData = json_decode($lockJson, true);
- $lockStatus = $lockData['lock_status'];
- if($lockStatus) { // 请求锁开启
- $requestTime = $lockData['request_time'];
- if($requestTime > time()) { // 请求锁截止时间大于当前时间,则不执行刷新请求
- Log::logInfo('【'.$corpid.'】本次请求gettoken接口触发锁限制', [
- 'request_time' => date('Y-m-d H:i:s'),
- 'lock_request_time' => date('Y-m-d H:i:s', $requestTime),
- 'lock_status' => $lockStatus
- ], 'GetAccessTokenTrace');
- return false;
- }
- }
- }
- $corpInfo = config('qyWechat.corp_info');
- $secret = $corpInfo[$corpid] ?? null;
- Log::logInfo('【'.$corpid.'】这是我的secret'.$secret, [], 'GetAccessTokenTrace');
- $redisKey = AccessTokenService::ACCESS_TOKEN_RDS. '_' .$corpid;
- # 获取令牌API地址
- $apiRefreshTokenUrl = config('qyWechat.get_access_token');
- $apiRefreshTokenUrl .= $corpid .'&corpsecret='.$secret;
- Log::logInfo('【'.$corpid.'】获取AccessToken链接:'.$apiRefreshTokenUrl, [], 'GetAccessTokenTrace');
- $response = HttpService::httpGet($apiRefreshTokenUrl);
- Log::logInfo('【'.$corpid.'】请求来源信息:'. $from, [
- 'response' => $response
- ], 'RequestAccessTokenFrom');
- $responseData = json_decode($response, true);
- Log::logInfo('【'.$corpid.'】这是我的请求结果', ['response' => $responseData], 'GetAccessTokenTrace');
- if(empty($responseData) || (isset($responseData['errcode']) && $responseData['errcode'])) {
- $errCode = isset($responseData['errcode']) ? $responseData['errcode'] : '';
- if($errCode == 45009) { // 提示Api请求超限,设置请求锁
- AccessTokenService::setRequestLock($corpid, time() + 6*60, 1);
- }
- Log::logInfo('【'.$corpid.'】获取失败了……', $responseData, 'GetAccessTokenTrace');
- Log::logError('【'.$corpid.'】第三方平台令牌获取API请求响应结果异常', $responseData, 'RefreshAccessToken');
- return false;
- } else {
- Log::logInfo('【'.$corpid.'】获取令牌成功', $responseData, 'GetAccessTokenTrace');
- Log::logInfo('【'.$corpid.'】第三方平台令牌获取API请求响应成功', $responseData, 'RefreshAccessTokenSuccess');
- }
- $accessToken = $responseData['access_token'];
- $saveData = [
- 'access_token' => $accessToken,
- 'expire' => $responseData['expires_in'] + time(),
- 'update_time' => time() + 3600
- ];
- # 解除AccessToken请求锁
- AccessTokenService::setRequestLock($corpid, time(), 0);
- # 将accessToken存入Redis
- RedisModel::set($redisKey, json_encode($saveData));
- RedisModel::expire($redisKey, 7200);
- Log::logError('Redis KEY值为:', [
- 'key' => $redisKey,
- 'value' => $accessToken,
- 'corpid' => $corpid
- ], 'refreshAccessTokenSave');
- return 0;
- }
- /**
- * 设置AccessToken请求锁
- * @param $corpid string 企业id
- * @param $requestTime integer 下次允许请求刷新令牌的时间戳
- * @param $lockStatus integer 锁状态 0关闭 1打开
- * */
- public static function setRequestLock($corpid, $requestTime, $lockStatus)
- {
- $lockInfo = [
- 'request_time' => $requestTime,
- 'lock_status' => $lockStatus
- ];
- RedisModel::set(AccessTokenService::ACCESS_TOKEN_REQUEST_LOCK . $corpid, json_encode($lockInfo));
- }
- }
|