<?php
namespace Yurun\OAuthLogin\Alipay;
use Yurun\OAuthLogin\Base;
use Yurun\OAuthLogin\ApiException;
class OAuth2 extends Base
{
const API_DOMAIN = 'https://openapi.alipay.com/gateway.do';
public $scope;
public $signType = 'RSA2';
public $appAuthToken;
public $appPrivateKey;
public $appPrivateKeyFile;
public function getAuthUrl($callbackUrl = null, $state = null, $scope = null)
{
$option = array(
'app_id' => $this->appid,
'scope' => $scope ? $scope : 'auth_user',
'redirect_uri' => null === $callbackUrl ? $this->callbackUrl : $callbackUrl,
'state' => $this->getState($state),
);
if(null === $this->loginAgentUrl)
{
return 'https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?' . $this->http_build_query($option);
}
else
{
return $this->loginAgentUrl . '?' . $this->http_build_query($option);
}
}
protected function __getAccessToken($storeState, $code = null, $state = null)
{
$params = array(
'app_id' => $this->appid,
'method' => 'alipay.system.oauth.token',
'charset' => 'utf-8',
'sign_type' => $this->signType,
'timestamp' => date('Y-m-d H:i:s'),
'version' => '1.0',
'grant_type' => 'authorization_code',
'code' => isset($code) ? $code : (isset($_GET['auth_code']) ? $_GET['auth_code'] : ''),
);
if($this->appAuthToken)
{
$params['app_auth_token'] = $this->appAuthToken;
}
$params['sign'] = $this->sign($params);
$response = $this->http->get(static::API_DOMAIN, $params);
$this->result = $response->json(true);
if(!isset($this->result['alipay_system_oauth_token_response']) && isset($this->result['error_response']))
{
throw new ApiException(sprintf('%s %s', $this->result['error_response']['msg'], $this->result['error_response']['sub_msg']), $this->result['error_response']['code']);
}
$this->result = $responseData = $this->result['alipay_system_oauth_token_response'];
if(isset($responseData['code']))
{
throw new ApiException(sprintf('%s %s', $responseData['msg'], $responseData['sub_msg']), $responseData['code']);
}
$this->openid = $responseData['user_id'];
return $this->accessToken = $responseData['access_token'];
}
public function getUserInfo($accessToken = null)
{
$params = array(
'app_id' => $this->appid,
'method' => 'alipay.user.info.share',
'charset' => 'utf-8',
'sign_type' => $this->signType,
'timestamp' => date('Y-m-d H:i:s'),
'version' => '1.0',
'auth_token' => null === $accessToken ? $this->accessToken : $accessToken,
);
if($this->appAuthToken)
{
$params['app_auth_token'] = $this->appAuthToken;
}
$params['sign'] = $this->sign($params);
$response = $this->http->get(static::API_DOMAIN, $params);
$this->result = $response->json(true);
if(!isset($this->result['alipay_user_info_share_response']) && isset($this->result['error_response']))
{
throw new ApiException(sprintf('%s %s', $this->result['error_response']['msg'], $this->result['error_response']['sub_msg']), $this->result['error_response']['code']);
}
$this->result = $responseData = $this->result['alipay_user_info_share_response'];
if(isset($responseData['code']) && 10000 != $responseData['code'])
{
throw new ApiException(sprintf('%s %s', $responseData['msg'], $responseData['sub_msg']), $responseData['code']);
}
return $responseData;
}
public function refreshToken($refreshToken)
{
$params = array(
'app_id' => $this->appid,
'method' => 'alipay.system.oauth.token',
'charset' => 'utf-8',
'sign_type' => $this->signType,
'timestamp' => date('Y-m-d H:i:s'),
'version' => '1.0',
'grant_type' => 'refresh_token',
'refresh_token' => $refreshToken,
);
if($this->appAuthToken)
{
$params['app_auth_token'] = $this->appAuthToken;
}
$params['sign'] = $this->sign($params);
$response = $this->http->get(static::API_DOMAIN, $params);
$this->result = $response->json(true);
if(!isset($this->result['alipay_system_oauth_token_response']) && isset($this->result['error_response']))
{
throw new ApiException(sprintf('%s %s', $this->result['error_response']['msg'], $this->result['error_response']['sub_msg']), $this->result['error_response']['code']);
}
$this->result = $responseData = $this->result['alipay_system_oauth_token_response'];
if(isset($responseData['code']))
{
throw new ApiException(sprintf('%s %s', $responseData['msg'], $responseData['sub_msg']), $responseData['code']);
}
$this->openid = $responseData['user_id'];
return $this->accessToken = $responseData['access_token'];
}
public function validateAccessToken($accessToken = null)
{
try
{
$this->getUserInfo($accessToken);
return true;
}
catch(ApiException $e)
{
return false;
}
}
public function sign($data)
{
$content = $this->parseSignData($data);
if(empty($this->appPrivateKeyFile))
{
$key = $this->appPrivateKey;
$method = 'signPrivate';
}
else
{
$key = $this->appPrivateKeyFile;
$method = 'signPrivateFromFile';
}
switch($this->signType)
{
case 'RSA':
$result = \Yurun\OAuthLogin\Lib\RSA::$method($content, $key);
break;
case 'RSA2':
$result = \Yurun\OAuthLogin\Lib\RSA2::$method($content, $key);
break;
default:
throw new \Exception('未知的加密方式:' . $this->signType);
}
return \base64_encode($result);
}
public function parseSignData($data)
{
if(isset($data['sign']))
{
unset($data['sign']);
}
\ksort($data);
$content = '';
foreach ($data as $k => $v){
if($v !== '' && $v !== null && !is_array($v)){
$content .= $k . '=' . $v . '&';
}
}
return trim($content, '&');
}
}