forked from modstart/ModStartCMS
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
228 changed files
with
32,844 additions
and
66 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
126 changes: 126 additions & 0 deletions
126
module/DataAliyunOssFe/Admin/Controller/ConfigController.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
<?php | ||
|
||
namespace Module\DataAliyunOssFe\Admin\Controller; | ||
|
||
use Illuminate\Routing\Controller; | ||
use ModStart\Admin\Layout\AdminConfigBuilder; | ||
use ModStart\Support\Concern\HasFields; | ||
|
||
class ConfigController extends Controller | ||
{ | ||
public function index(AdminConfigBuilder $builder) | ||
{ | ||
$builder->pageTitle('阿里云OSS存储(前端直传)'); | ||
/** @var HasFields $builder */ | ||
$builder->layoutPanel('公共配置', function ($builder) { | ||
/** @var HasFields $builder */ | ||
$builder->switch('DataAliyunOssFe_Enable', '启用'); | ||
$builder->select('DataAliyunOssFe_Region', '地区') | ||
->options([ | ||
'cn-hangzhou' => '华东1(杭州)', | ||
'cn-shanghai' => '华东2(上海)', | ||
'cn-qingdao' => '华北1(青岛)', | ||
'cn-beijing' => '华北2(北京)', | ||
'cn-zhangjiakou' => '华北3(张家口)', | ||
'cn-huhehaote' => '华北5(呼和浩特)', | ||
'cn-shenzhen' => '华南1(深圳)', | ||
'cn-hongkong' => '中国(香港)', | ||
'ap-southeast-1' => '亚太东南1(新加坡)', | ||
'ap-southeast-2' => '亚太东南2(悉尼)', | ||
'ap-southeast-3' => '亚太东南3(吉隆坡)', | ||
'ap-southeast-5' => '亚太东南5(雅加达)', | ||
'ap-south-1' => '亚太南部1(孟买)', | ||
'ap-northeast-1' => '亚太东北1(东京)', | ||
'ap-northeast-2' => '亚太东北2(首尔)', | ||
'ap-south-1' => '亚太南部1(孟买)', | ||
'eu-central-1' => '欧洲中部1(法兰克福)', | ||
'eu-west-1' => '欧洲西部1(伦敦)', | ||
'me-east-1' => '中东东部1(迪拜)', | ||
'us-west-1' => '美国西部1(硅谷)', | ||
'us-east-1' => '美国东部1(弗吉尼亚)', | ||
'ap-northeast-1' => '亚太东北1(东京)', | ||
'ap-southeast-1' => '亚太东南1(新加坡)', | ||
'ap-southeast-2' => '亚太东南2(悉尼)', | ||
]); | ||
$builder->text('DataAliyunOssFe_Bucket', 'Bucket'); | ||
$builder->text('DataAliyunOssFe_Endpoint', 'Endpoint') | ||
->help('格式为 oss-cn-xxx.aliyuncs.com'); | ||
$builder->text('DataAliyunOssFe_Domain', 'Bucket域名') | ||
->help('如果您的OSS开启了CDN加速,可直接配置CDN域名(如 http://xxx.oss-cn-xxx.aliyuncs.com)') | ||
->ruleUrl(); | ||
}); | ||
|
||
$builder->layoutPanel('服务端配置', function ($builder) { | ||
/** @var HasFields $builder */ | ||
|
||
$builder->html('', '配置说明')->htmlContentFromMarkdown( | ||
' | ||
**用于 OSS 文件的增删改查管理** | ||
需要开通 OSS 上传权限,权限策略参考内容如下: | ||
``` | ||
{ | ||
"Version": "1", | ||
"Statement": [ | ||
{ | ||
"Effect": "Allow", | ||
"Action": [ | ||
"oss:Get*", | ||
"oss:Put*", | ||
"oss:DeleteObject" | ||
], | ||
"Resource": [ | ||
"acs:oss:*:*:test-oss", | ||
"acs:oss:*:*:test-oss/*" | ||
] | ||
} | ||
] | ||
} | ||
``` | ||
' | ||
); | ||
$builder->text('DataAliyunOssFe_AccessKeyId', 'AccessKeyId'); | ||
$builder->text('DataAliyunOssFe_AccessKeySecret', 'AccessKeySecret'); | ||
}); | ||
|
||
$builder->layoutPanel('前端配置', function ($builder) { | ||
/** @var HasFields $builder */ | ||
$builder->html('', '账号说明')->htmlContentFromMarkdown( | ||
' | ||
**用户前端受限的上传权限** | ||
需要开通 | ||
① OSS 上传权限,权限策略参考内容如下: | ||
```json | ||
{ | ||
"Version": "1", | ||
"Statement": [ | ||
{ | ||
"Effect": "Allow", | ||
"Action": "oss:PutObject", | ||
"Resource": "acs:oss:*:*:test-oss/data_temp/*" | ||
} | ||
] | ||
} | ||
``` | ||
② STS 服务权限 | ||
需要开通 AliyunSTSAssumeRoleAccess 系统策略。 | ||
' | ||
); | ||
$builder->text('DataAliyunOssFe_Front_AccessKeyId', 'AccessKeyId'); | ||
$builder->text('DataAliyunOssFe_Front_AccessKeySecret', 'AccessKeySecret'); | ||
$builder->text('DataAliyunOssFe_Front_StsEndpoint', 'StsEndpoint') | ||
->help('例如 sts.cn-shanghai.aliyuncs.com ,查看对应地区 <a target="_blank" href="https://help.aliyun.com/zh/ram/developer-reference/api-sts-2015-04-01-endpoint">Endpoint</a>'); | ||
$builder->text('DataAliyunOssFe_Front_RoleArn', 'RoleArn') | ||
->help('例如 acs:ram::148316xxxxxxxxx:role/ms-oss-test-fe'); | ||
}); | ||
|
||
$builder->formClass('wide'); | ||
return $builder->perform(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<?php | ||
|
||
/* @var \Illuminate\Routing\Router $router */ | ||
|
||
$router->match(['get', 'post'], 'data_aliyun_oss_fe/config', 'ConfigController@index'); | ||
|
225 changes: 225 additions & 0 deletions
225
module/DataAliyunOssFe/Core/DataAliyunOssFeDataStorage.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,225 @@ | ||
<?php | ||
|
||
|
||
namespace Module\DataAliyunOssFe\Core; | ||
|
||
use AlibabaCloud\SDK\Sts\V20150401\Models\AssumeRoleRequest; | ||
use AlibabaCloud\SDK\Sts\V20150401\Sts; | ||
use AlibabaCloud\Tea\Utils\Utils\RuntimeOptions; | ||
use Darabonba\OpenApi\Models\Config; | ||
use Illuminate\Support\Facades\Cache; | ||
use ModStart\Core\Exception\BizException; | ||
use ModStart\Core\Input\Response; | ||
use ModStart\Core\Util\PathUtil; | ||
use ModStart\Data\AbstractDataStorage; | ||
use ModStart\Data\Event\DataFileUploadedEvent; | ||
use Module\DataAliyunOssFe\Util\DataAliyunOssFeUtil; | ||
use OSS\Core\OssException; | ||
use OSS\OssClient; | ||
|
||
class DataAliyunOssFeDataStorage extends AbstractDataStorage | ||
{ | ||
/** | ||
* @var OssClient | ||
*/ | ||
private $client; | ||
private $bucket; | ||
|
||
public function init() | ||
{ | ||
DataAliyunOssFeUtil::init(); | ||
$this->client = new OssClient( | ||
$this->option['accessKeyId'], | ||
$this->option['accessKeySecret'], | ||
$this->option['endpoint'] | ||
); | ||
$this->bucket = $this->option['bucket']; | ||
} | ||
|
||
public function driverName() | ||
{ | ||
return 'AliyunOss'; | ||
} | ||
|
||
|
||
public function has($file) | ||
{ | ||
try { | ||
$ret = $this->client->getObjectMeta($this->bucket, $file); | ||
if (empty($ret['etag'])) { | ||
return false; | ||
} | ||
return true; | ||
} catch (\Exception $e) { | ||
return false; | ||
} | ||
} | ||
|
||
public function move($from, $to) | ||
{ | ||
try { | ||
$this->client->copyObject($this->bucket, $from, $this->bucket, $to); | ||
} catch (OssException $e) { | ||
if (str_contains($e->getMessage(), 'NoSuchKey')) { | ||
} else { | ||
throw $e; | ||
} | ||
} | ||
try { | ||
$this->client->deleteObject($this->bucket, $from); | ||
} catch (\Exception $e) { | ||
if (str_contains($e->getMessage(), 'NoSuchKey')) { | ||
} else { | ||
throw $e; | ||
} | ||
} | ||
} | ||
|
||
public function delete($file) | ||
{ | ||
try { | ||
$ret = $this->client->deleteObject($this->bucket, $file); | ||
} catch (\Exception $e) { | ||
if (str_contains($e->getMessage(), 'NoSuchKey')) { | ||
} else { | ||
throw $e; | ||
} | ||
} | ||
} | ||
|
||
public function put($file, $content) | ||
{ | ||
$this->client->putObject($this->bucket, $file, $content); | ||
} | ||
|
||
public function get($file) | ||
{ | ||
return $this->client->getObject($this->bucket, $file); | ||
} | ||
|
||
public function size($file) | ||
{ | ||
try { | ||
$ret = $this->client->getObjectMeta($this->bucket, $file); | ||
return intval($ret['content-length']); | ||
} catch (\Exception $e) { | ||
return 0; | ||
} | ||
} | ||
|
||
public function getUploadConfig() | ||
{ | ||
return Cache::remember('DataAliyunOssFe:Config', 30, function () { | ||
DataAliyunOssFeUtil::init(); | ||
$bucket = modstart_config('DataAliyunOssFe_Bucket'); | ||
$config = new Config([ | ||
"accessKeyId" => modstart_config('DataAliyunOssFe_Front_AccessKeyId'), | ||
"accessKeySecret" => modstart_config('DataAliyunOssFe_Front_AccessKeySecret'), | ||
]); | ||
|
||
$config->endpoint = modstart_config('DataAliyunOssFe_Front_StsEndpoint'); | ||
$client = new Sts($config); | ||
|
||
$assumeRoleRequest = new AssumeRoleRequest([ | ||
// roleArn填写步骤2获取的角色ARN | ||
"roleArn" => modstart_config('DataAliyunOssFe_Front_RoleArn'), | ||
// roleSessionName用于自定义角色会话名称,用来区分不同的令牌,例如填写为sessiontest。 | ||
"roleSessionName" => "upload-to-data-temp", | ||
// durationSeconds用于设置临时访问凭证有效时间单位为秒,最小值为900,最大值以当前角色设定的最大会话时间为准。本示例指定有效时间为3000秒。 | ||
"durationSeconds" => 3600, | ||
// policy填写自定义权限策略,用于进一步限制STS临时访问凭证的权限。 | ||
// 如果不指定Policy,则返回的STS临时访问凭证默认拥有指定角色的所有权限。 | ||
// 临时访问凭证最后获得的权限是步骤4设置的角色权限和该Policy设置权限的交集。 | ||
"policy" => '{ | ||
"Version": "1", | ||
"Statement": [ | ||
{ | ||
"Effect": "Allow", | ||
"Action": "oss:PutObject", | ||
"Resource": "acs:oss:*:*:' . $bucket . '/data_temp/*" | ||
} | ||
] | ||
}', | ||
]); | ||
$runtime = new RuntimeOptions([]); | ||
$result = $client->assumeRoleWithOptions($assumeRoleRequest, $runtime); | ||
return [ | ||
'region' => 'oss-' . modstart_config('DataAliyunOssFe_Region'), | ||
'bucket' => $bucket, | ||
'accessKeyId' => $result->body->credentials->accessKeyId, | ||
'accessKeySecret' => $result->body->credentials->accessKeySecret, | ||
'securityToken' => $result->body->credentials->securityToken, | ||
'expiration' => $result->body->credentials->expiration, | ||
]; | ||
}); | ||
} | ||
|
||
public function multiPartInit($param) | ||
{ | ||
$token = $this->multiPartInitToken($param); | ||
$this->uploadChunkTokenAndUpdateToken($token); | ||
$token['uploadConfig'] = $this->getUploadConfig(); | ||
return Response::generateSuccessData($token); | ||
} | ||
|
||
public function multiPartUploadEnd($param) | ||
{ | ||
$category = $param['category']; | ||
$token = $this->multiPartInitToken($param); | ||
BizException::throwsIfEmpty('DataAliyunOssFe.TokenEmpty', $token); | ||
DataFileUploadedEvent::fire('AliyunOss', $category, $token['fullPath'], isset($param['eventOpt']) ? $param['eventOpt'] : []); | ||
$dataTemp = $this->repository->addTemp($category, $token['path'], $token['name'], $token['size'], empty($token['md5']) ? null : $token['md5']); | ||
$data['data'] = $dataTemp; | ||
$data['path'] = $token['fullPath']; | ||
$data['preview'] = $this->getDriverFullPath($token['fullPath']); | ||
$data['finished'] = true; | ||
$this->uploadChunkTokenAndDeleteToken($token); | ||
return Response::generateSuccessData($data); | ||
} | ||
|
||
public function domain() | ||
{ | ||
return modstart_config()->getWithEnv('DataAliyunOssFe_Domain'); | ||
} | ||
|
||
public function domainInternal() | ||
{ | ||
return modstart_config()->getWithEnv('DataAliyunOssFe_DomainInternal', modstart_config()->getWithEnv('DataAliyunOssFe_Domain')); | ||
} | ||
|
||
|
||
public function updateDriverDomain($data) | ||
{ | ||
$update = [ | ||
'driver' => 'AliyunOss', | ||
'domain' => $this->domain(), | ||
]; | ||
$this->repository->updateData($data['id'], $update); | ||
return array_merge($data, $update); | ||
} | ||
|
||
public function getDriverFullPath($path) | ||
{ | ||
$path = parent::getDriverFullPath($path); | ||
if (PathUtil::isPublicNetPath($path)) { | ||
return $path; | ||
} | ||
return $this->domain() . $path; | ||
} | ||
|
||
/** | ||
* @param $path | ||
* @return mixed|string | ||
* @deprecated delete at 2024-04-25 | ||
*/ | ||
public function getDriverFullPathInternal($path) | ||
{ | ||
$path = parent::getDriverFullPathInternal($path); | ||
if (PathUtil::isPublicNetPath($path)) { | ||
return $path; | ||
} | ||
return $this->domainInternal() . $path; | ||
} | ||
|
||
|
||
} |
Oops, something went wrong.