Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
XueSiLf committed Sep 23, 2021
1 parent e2cc99b commit 0206123
Show file tree
Hide file tree
Showing 15 changed files with 649 additions and 150 deletions.
22 changes: 10 additions & 12 deletions src/OpenPlatform/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class Application extends ServiceContainer
* @param AccessToken|null $accessToken
* @return OfficialAccount
*/
public function officialAccount(string $appId, string $refreshToken = null, AccessToken $accessToken = null, $reUseLoggerCache = false): OfficialAccount
public function officialAccount(string $appId, string $refreshToken = null, AccessToken $accessToken = null): OfficialAccount
{
$officialAccount = new OfficialAccount($this->getAuthorizerConfig($appId, $refreshToken), null, [
ServiceProviders::AccessToken => $accessToken ?: function ($app) {
Expand All @@ -84,11 +84,10 @@ public function officialAccount(string $appId, string $refreshToken = null, Acce
}
]);

if ($reUseLoggerCache) {
foreach ([ServiceProviders::Cache, ServiceProviders::Logger] as $reuse) {
if (isset($this[$reuse])) {
$officialAccount[$reuse] = $this[$reuse];
}
// 复用开放平台的logger cache为授权公众号提供服务
foreach ([ServiceProviders::Cache, ServiceProviders::Logger] as $reuse) {
if (isset($this[$reuse])) {
$officialAccount[$reuse] = $this[$reuse];
}
}

Expand All @@ -104,7 +103,7 @@ public function officialAccount(string $appId, string $refreshToken = null, Acce
* @param AccessToken|null $accessToken
* @return MiniProgram
*/
public function miniProgram(string $appId, string $refreshToken = null, AccessToken $accessToken = null, $reUseLoggerCache = false): MiniProgram
public function miniProgram(string $appId, string $refreshToken = null, AccessToken $accessToken = null): MiniProgram
{
$miniProgram = new MiniProgram($this->getAuthorizerConfig($appId, $refreshToken), null, [
ServiceProviders::AccessToken => $accessToken ?: function ($app) {
Expand All @@ -121,11 +120,10 @@ public function miniProgram(string $appId, string $refreshToken = null, AccessTo
}
]);

if ($reUseLoggerCache) {
foreach ([ServiceProviders::Cache, ServiceProviders::Logger] as $reuse) {
if (isset($this[$reuse])) {
$miniProgram[$reuse] = $this[$reuse];
}
// 复用开放平台的logger cache为授权小程序提供服务
foreach ([ServiceProviders::Cache, ServiceProviders::Logger] as $reuse) {
if (isset($this[$reuse])) {
$miniProgram[$reuse] = $this[$reuse];
}
}

Expand Down
156 changes: 155 additions & 1 deletion src/Work/Server/Guard.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,23 @@

namespace EasySwoole\WeChat\Work\Server;

use EasySwoole\WeChat\Kernel\Contracts\MessageInterface;
use EasySwoole\WeChat\Kernel\Contracts\RequestMessageInterface;
use EasySwoole\WeChat\Kernel\Exceptions\BadRequestException;
use EasySwoole\WeChat\Kernel\Exceptions\InvalidArgumentException;
use EasySwoole\WeChat\Kernel\Exceptions\RuntimeException;
use EasySwoole\WeChat\Kernel\Messages\News;
use EasySwoole\WeChat\Kernel\Messages\NewsItem;
use EasySwoole\WeChat\Kernel\Messages\Raw;
use EasySwoole\WeChat\Kernel\Messages\Text;
use EasySwoole\WeChat\Kernel\Psr\Response;
use EasySwoole\WeChat\Kernel\ServerGuard;
use EasySwoole\WeChat\Kernel\ServiceProviders;
use EasySwoole\WeChat\Kernel\Utility\XML;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use EasySwoole\WeChat\Kernel\Messages\Message;
use Throwable;

/**
* Class Guard
Expand All @@ -24,6 +37,147 @@ public function isValidateRequest(ServerRequestInterface $request): bool
return isset($request->getQueryParams()['echostr']);
}

/**
* @param ServerRequestInterface $request
* @return bool
*/
public function isSafeMode(ServerRequestInterface $request): bool
{
return true;
}

/**
* @param ServerRequestInterface $request
* @return $this
* @throws BadRequestException
*/
public function validate(ServerRequestInterface $request): ServerGuard
{
if (!$this->alwaysValidate && !$this->isSafeMode($request)) {
return $this;
}

if (empty($request->getQueryParams()['msg_signature'])
|| empty($request->getQueryParams()['timestamp'])
|| empty($request->getQueryParams()['nonce'])
) {
throw new BadRequestException('Invalid request params.', 400);
}

if (!$this->isValidateRequest($request)) {
$postContent = $request->getBody()->getContents();
if (0 === stripos($postContent, '<')) {
$postContent = XML::parse($postContent);
} else {
throw new BadRequestException('Invalid request body.', 400);
}

if (empty($postContent) || !is_array($postContent)) {
throw new BadRequestException('No message received.');
}

$makeSignature = $this->signature(
$this->getToken(),
$request->getQueryParams()['timestamp'] ?? "",
$request->getQueryParams()['nonce'] ?? "",
$postContent['Encrypt']
);
} else {
// echostr 签名校验
$makeSignature = $this->signature(
$this->getToken(),
$request->getQueryParams()['timestamp'] ?? "",
$request->getQueryParams()['nonce'] ?? "",
$request->getQueryParams()['echostr']
);
}

if (($request->getQueryParams()['msg_signature'] ?? "") !== $makeSignature) {
throw new BadRequestException('Invalid request signature.', 400);
}

return $this;
}

/**
* @param ServerRequestInterface $request
* @return ResponseInterface
* @throws Throwable
*/
protected function resolve(ServerRequestInterface $request): ResponseInterface
{
if ($this->isValidateRequest($request)) {
$replyMessage = $this->dispatch(Message::VALIDATE, $request);
} else {
$requestMessage = $this->parseRequest($request);
$replyMessage = $this->dispatch($requestMessage->getType(), $requestMessage);
}

/**
* "", []
*/
if ((empty($replyMessage) && ($replyMessage !== 0 && $replyMessage !== "0"))) {
return new Response(
200,
['Content-Type' => 'application/text'],
''
);
}

if ($replyMessage instanceof Raw) {
$replyString = $replyMessage->__toString();
} else {
if (is_string($replyMessage) || is_numeric($replyMessage)) {
$replyMessage = new Text($replyMessage);
} elseif (is_array($replyMessage) && reset($replyMessage) instanceof NewsItem) {
$replyMessage = new News($replyMessage);
}

if (!$replyMessage instanceof MessageInterface) {
throw new InvalidArgumentException(sprintf('Invalid Messages type "%s".', gettype($replyMessage)));
}

/** 除非 Message::VALIDATE 出了问题 否则不会走走这里 */
if (!isset($requestMessage)) {
throw new RuntimeException("Invalid request message.");
}
$replyString = $this->buildReply($requestMessage->getFromUserName(), $requestMessage->getToUserName(), $replyMessage);
}

if ($this->isSafeMode($request) && !$this->isValidateRequest($request)) {
$encrypted = $this->app[ServiceProviders::Encryptor]->encrypt(
$replyString,
$this->app[ServiceProviders::Config]->get("aesKey"),
$this->app[ServiceProviders::Config]->get("corpId")
);
$replyString = $this->buildEncryptedReply($encrypted);
}

return new Response(
200,
['Content-Type' => 'application/xml'],
$replyString
);
}


/**
* @param array $message
* @return string|null
*/
protected function decryptMessage(array $message): ?string
{
$configs = $this->app->getConfig();
$appId = $configs['corpId'];
$aesKey = $configs['aesKey'];

return $this->app[ServiceProviders::Encryptor]->decrypt(
$message['Encrypt'],
$aesKey,
$appId
);
}

/**
* @param array $message
* @return RequestMessageInterface
Expand Down Expand Up @@ -63,4 +217,4 @@ public function toXmlArray(): array
}
};
}
}
}
28 changes: 26 additions & 2 deletions src/Work/Server/Handlers/EchoStrHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
namespace EasySwoole\WeChat\Work\Server\Handlers;

use EasySwoole\WeChat\Kernel\Contracts\EventHandlerInterface;
use EasySwoole\WeChat\Kernel\Encryptor;
use EasySwoole\WeChat\Kernel\Messages\Raw;
use EasySwoole\WeChat\Kernel\ServiceProviders;
use Pimple\Container;
use Psr\Http\Message\ServerRequestInterface;

/**
Expand All @@ -14,15 +17,36 @@
*/
class EchoStrHandler implements EventHandlerInterface
{
/**
* @var Container
*/
protected $app;

/**
* EchoStrHandler constructor.
* @param Container $app
*/
public function __construct(Container $app)
{
$this->app = $app;
}

public function handle($request = null)
{
if ($request instanceof ServerRequestInterface) {
$str = $request->getQueryParams()['echostr'] ?? null;
$echoStr = $request->getQueryParams()['echostr'] ?? null;
/** @var Encryptor $encryptor */
$encryptor = $this->app[ServiceProviders::Encryptor];
$str = $encryptor->decrypt(
$echoStr,
$this->app[ServiceProviders::Config]->get('aesKey'),
$this->app[ServiceProviders::Config]->get('corpId')
);
if (!is_null($str)) {
return new Raw($str);
}
}

return null;
}
}
}
2 changes: 1 addition & 1 deletion src/Work/Server/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public function register(Container $app)
if (!isset($app[Application::Server])) {
$app[Application::Server] = function (ServiceContainer $app) {
$guard = new Guard($app);
$guard->push(new EchoStrHandler(), Message::VALIDATE);
$guard->push(new EchoStrHandler($app), Message::VALIDATE);
return $guard;
};
}
Expand Down
13 changes: 10 additions & 3 deletions tests/Mock/Message/ServerRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,15 @@ public function __construct($method = 'GET', Uri $uri = null, array $headers = n
$query = [];
foreach (explode("&", $this->getUri()->getQuery()) as $group) {
if (!empty($group)) {
$group = explode("=", $group);
$query[$group[0]] = $group[1];
$groupArr = explode("=", $group);

// 针对 value 有 = 符号的做兼容
if ($groupArr > 2) {
$firstPos = strpos($group, '=');
$query[$groupArr[0]] = substr($group, $firstPos + 1);
} else {
$query[$groupArr[0]] = $groupArr[1];
}
}
}
$this->withQueryParams($query);
Expand Down Expand Up @@ -146,4 +153,4 @@ public function withoutAttribute($name)
unset($this->attributes[$name]);
return $this;
}
}
}
23 changes: 23 additions & 0 deletions tests/OpenPlatform/ApplicationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
use EasySwoole\WeChat\OpenPlatform\Application;
use EasySwoole\WeChat\OpenPlatform\Authorizer\OfficialAccount\Application as OfficialAccount;
use EasySwoole\WeChat\Tests\Mock\Message\Status;
use EasySwoole\WeChat\Tests\OpenPlatform\Util\MockCache;
use EasySwoole\WeChat\Tests\OpenPlatform\Util\MockLogger;
use EasySwoole\WeChat\Tests\TestCase;
use Psr\Http\Message\ServerRequestInterface;
use EasySwoole\WeChat\OpenPlatform\Base;
Expand Down Expand Up @@ -209,6 +211,27 @@ public function testDynamicCalls2()
$this->assertSame(json_decode($this->readMockResponseJson('createPreAuthorizationCode.json'), true), $client->createPreAuthorizationCode());
}

// 保证开放平台授权的应用和开放平台原本的 logger 和 cache 保持一致
public function testLogger()
{
$app = new Application([
'appId' => 'component-app-id',
'appSecret' => 'component-secret',
'token' => 'component-token',
'aesKey' => 'Qqx2S6jV3mp5prWPg5x3eBmeU1kLayZio4Q9ZxWTbmf']);

$app->rebind(ServiceProviders::Logger, new MockLogger());
$app->rebind(ServiceProviders::Cache, new MockCache());

$miniProgram = $app->miniProgram('mock_miniProgram_app_id', 'mock_miniProgram_refresh-token');
$this->assertSame($app->logger, $miniProgram->logger);
$this->assertSame($app->cache, $miniProgram->cache);

$officialAccount = $app->officialAccount('mock_officialAccount_app_id', 'mock_officialAccount_refresh-token');
$this->assertSame($app->logger, $officialAccount->logger);
$this->assertSame($app->cache, $officialAccount->cache);
}

protected function readMockResponseJson(string $file): string
{
return file_get_contents(dirname(__FILE__) . '/Base/mock_data/' . $file);
Expand Down
Loading

0 comments on commit 0206123

Please sign in to comment.