Compare commits

..

10 Commits

Author SHA1 Message Date
1aedddc66e feat: update package name 2024-06-12 22:02:42 +00:00
dongwei
445f9dd037 add docker ip 2019-02-28 14:20:42 +08:00
George Xie
436a084581 非生产环境的 server 不对检查客户端 ip 白名单 2018-06-26 10:50:49 +08:00
George Xie
6c54737d13 将每个服务的 client 改为单例,修正重入问题 2018-06-22 20:21:08 +08:00
候学杰
5aaeaa0499 bug fix 2018-03-19 17:01:14 +08:00
候学杰
1700ac3c87 Update README.md 2018-03-19 16:49:18 +08:00
候学杰
33ca037634 bug fix 2018-03-19 16:39:20 +08:00
候学杰
d1d1802b14 namespace 2018-03-19 16:36:30 +08:00
候学杰
87970d17ae package name 2018-03-19 16:33:35 +08:00
候学杰
d86fe14e49 readme 2018-03-19 16:28:53 +08:00
9 changed files with 266 additions and 1303 deletions

102
README.md Normal file
View File

@ -0,0 +1,102 @@
# Internal API Server/Client(PHP版)
> 该项目使用 composer 来完成加载
执行
```bash
composer config repositories.php-internal-api-client vcs git@git.int.haowumc.com:arch/php-internal-api-client.git
composer require arch/php-internal-api-client
```
### 如何使用
#### Server
* 注册中间件
```php
$app->routeMiddleware([
'internal' => PdInternalApi\Middleware\InternalApi::class,
]);
```
* 增加配置文件:```config/internal_api.php``` , 在server数组中为调用方增加 secret。
```php
<?php
return [
/**
* 对内部其他系统提供api
*
* 格式为:
* 调用方标识 => 调用方secret
*/
'server' => [
// app id => app secret
'{{app name}}' => env('INTERNAL_SERVER_{{app name}}_SECRET'),
],
];
```
* 在项目 .env 文件中增加如下配置
```
INTERNAL_SERVER_{{app name}}_SECRET=323232323
```
* 在路由中启用中间件
```php
$route->group(['middleware'=>'internal'],function()use($router){
//这里添加对应路由
});
```
#### Client
* 注册服务
```PHP
$app->register(PdInternalApi\ServiceProvider::class);
```
* 增加配置文件:```config/internal_api.php``` , 在server数组中为调用方增加 secret。
```php
<?php
return [
/**
* 配置可以使用的内部系统
*/
'client' => [
/**
* key 为 api 项目的名称。
* 数组为该系统的配置,由该系统的负责人提供
*/
'{app name}' => [
'base_uri' => env('INTERNAL_CLIENT_{{app name}}_URI', ''),
'appid' => env('INTERNAL_CLIENT_{{app name}}_APPID', ''),
'secret' => env('INTERNAL_CLIENT_{{app name}}_SECRET', ''),
'timeout' => 30,
],
],
];
```
* 在项目 .env 文件中增加如下配置
```
INTERNAL_CLIENT_{app name}_URI=http://test.in.haowumc.com/
INTERNAL_CLIENT_{app name}_APPID=test
INTERNAL_CLIENT_{app name}_SECRET=sdfsdfsdf
```
* 调用
```php
$api = app('internal.api.{{app name}}')
$resp = $api->call('{{URI}}',$params);
```

View File

@ -1,5 +1,5 @@
{ {
"name": "pd_arch/internal_api", "name": "paidian/php-internal-api-client",
"type": "library", "type": "library",
"require": { "require": {
"guzzlehttp/guzzle": "^6.3", "guzzlehttp/guzzle": "^6.3",
@ -7,7 +7,7 @@
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"InternalApi\\": "src/" "PdInternalApi\\": "src/"
}, },
"files": [ "files": [
"src/helpers.php" "src/helpers.php"

1194
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,29 +1,19 @@
<?php <?php
namespace InternalApi; namespace PdInternalApi;
class Client class Client
{ {
protected $currentApp; protected $service_name;
protected $config; protected $config;
public function __construct($config) public function __construct($service_name, $config)
{ {
$this->service_name = $service_name;
$this->config = $config; $this->config = $config;
} }
/**
* @param $app
* @return $this
*/
public function app($app)
{
if (isset($this->config[$app]))
$this->currentApp = $app;
return $this;
}
/** /**
* 调用api如果状态码不为200则抛出异常 * 调用api如果状态码不为200则抛出异常
* @param $uri * @param $uri
@ -33,8 +23,7 @@ class Client
*/ */
public function call($uri, $params) public function call($uri, $params)
{ {
$config = array_merge(['timeout' => 3], $config = array_merge(['timeout' => 3], $this->config);
$this->config[$this->currentApp]);
$secret = $config['secret']; $secret = $config['secret'];
unset($config['secret']); unset($config['secret']);
$client = new \GuzzleHttp\Client($config); $client = new \GuzzleHttp\Client($config);
@ -42,10 +31,10 @@ class Client
$params['timestamp'] = time(); $params['timestamp'] = time();
$params['sign'] = sign($params, $secret); $params['sign'] = sign($params, $secret);
$resp = $client->post($uri, ['form_params' => $params]); $resp = $client->post($uri, ['form_params' => $params]);
if ($resp->getStatusCode() == 200) { if ($resp->getStatusCode() != 200) {
return \GuzzleHttp\json_decode($resp->getBody(), true); return false;
} }
return false; return \GuzzleHttp\json_decode($resp->getBody(), true);
} }
} }

View File

@ -1,68 +1,86 @@
<?php <?php
namespace InternalApi\Middleware; namespace PdInternalApi\Middleware;
use Closure; use Closure;
use Illuminate\Http\JsonResponse; use Illuminate\Http\JsonResponse;
use Illuminate\Support\Str; use Illuminate\Support\Str;
use function InternalApi\sign; use function PdInternalApi\sign;
class InternalApi class InternalApi
{ {
public function __construct() public function __construct()
{ {
app()->configure('internal_api'); app()->configure('internal_api');
} }
/** private function isClientIPPermitted($ip)
* Handle an incoming request. {
* if (!app()->environment('production', 'staging')) {
* @param \Illuminate\Http\Request $request return true;
* @param \Closure $next }
* @return mixed if (Str::startsWith($ip, [
*/ '127.0.0.1',
public function handle($request, Closure $next) //局域网
{ '192.168.',
$ip = $request->getClientIp(); //vpc
'10.0.',
if (!Str::startsWith($ip, [ //pod network
'127.0.0.', '192.168.', '10.0.' '172.20.',
])) { //北京办公区
return new JsonResponse('', 404); '172.16.'
} ])) {
return true;
$params = $request->all(); }
return false;
if (empty($params['appid'])) { }
$data = ['error' => 'require appid',];
return new JsonResponse($data, 403); /**
} * Handle an incoming request.
*
if (empty($params['timestamp'])) { * @param \Illuminate\Http\Request $request
$data = ['error' => 'require time',]; * @param \Closure $next
return new JsonResponse($data, 403); * @return mixed
} elseif (intval($params['timestamp']) + 60 < time()) { */
$data = ['error' => 'sign expired',]; public function handle($request, Closure $next)
return new JsonResponse($data, 403); {
} $ip = $request->getClientIp();
if (!$this->isClientIPPermitted($ip)) {
$key = config('internal_api.server.' . $params['appid']); return new JsonResponse("$ip is forbidden", 403);
}
if (empty($key)) {
$data = ['error' => 'config error',]; $params = $request->all();
return new JsonResponse($data, 403);
} if (empty($params['appid'])) {
$data = ['error' => 'require appid',];
$sign = sign($params, $key); return new JsonResponse($data, 403);
if ($sign != $params['sign']) { }
$data = [
'error' => 'sign error', if (empty($params['timestamp'])) {
]; $data = ['error' => 'require time',];
return new JsonResponse($data, 403); return new JsonResponse($data, 403);
} } else if (intval($params['timestamp']) + 60 < time()) {
$data = ['error' => 'sign expired',];
return $next($request); return new JsonResponse($data, 403);
} }
$key = config('internal_api.server.' . $params['appid']);
if (empty($key)) {
$data = ['error' => 'config error',];
return new JsonResponse($data, 403);
}
$sign = sign($params, $key);
if ($sign != $params['sign']) {
$data = [
'error' => 'sign error',
];
return new JsonResponse($data, 403);
}
return $next($request);
}
} }

40
src/ServiceProvider.php Normal file
View File

@ -0,0 +1,40 @@
<?php
namespace PdInternalApi;
use Illuminate\Http\Request;
class ServiceProvider extends \Illuminate\Support\ServiceProvider
{
public function boot(){
Request::setTrustedProxies([
//pod network
'172.20.0.0/16',
//vpc
'10.0.0.0/16',
//local
'127.0.0.1',
//北京办公区
'172.16.0.0/16',
//aliyun slb
'100.116.0.0/16',
], Request::HEADER_X_FORWARDED_ALL);
}
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->configure('internal_api');
foreach (config('internal_api.client') as $service_name => $config) {
$this->app->singleton('internal.api.' . $service_name, function () use ($service_name, $config) {
return new Client($service_name, $config);
});
}
}
}

View File

@ -1,28 +0,0 @@
<?php
namespace InternalApi\ServiceProvider;
use Illuminate\Support\ServiceProvider;
use InternalApi\Client;
class InternalApiServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->configure('internal_api');
$this->app->singleton('internal.api', function () {
return new Client(config('internal_api.client'));
});
foreach (config('internal_api.client') as $key => $config) {
$this->app->singleton('internal.api.' . $key, function () use ($key) {
return $this->app['internal.api']->app($key);
});
}
}
}

View File

@ -0,0 +1,36 @@
<?php
return [
/**
* 对内部其他系统提供api
*
* 格式为:
* 调用方标识 => 调用方secret
*/
'server' => [
// app id => app secret
'finance' => 'a249f0e40e31877adedd76fac6c6c116',
'mall' => '8b54fdc7b317906d93c83152be5f956b',
'xiaoke' => '8b54fdc7b317906d93c83152be5f956b',
],
/**
* 配置可以使用的内部系统
*/
'client' => [
/**
* key api 项目的名称。
* 数组为该系统的配置,由该系统的负责人提供
*/
'finance' => [
'base_uri' => env('INTERNAL_CLIENT_FINANCE_URI', ''),
'appid' => env('INTERNAL_CLIENT_FINANCE_APPID', ''),
'secret' => env('INTERNAL_CLIENT_FINANCE_SECRET', ''),
'timeout' => 30,
],
'mall' => [
'base_uri' => env('INTERNAL_CLIENT_MALL_URI', ''),
'appid' => env('INTERNAL_CLIENT_MALL_APPID', ''),
'secret' => env('INTERNAL_CLIENT_MALL_SECRET', ''),
'timeout' => 3,
],
],
];

View File

@ -1,6 +1,6 @@
<?php <?php
namespace InternalApi; namespace PdInternalApi;
/** /**
* 签名 * 签名