Browse Source

Merge pull request #4844 from Aprite/aliyun-200722

Improve the Aliyun blob storing integration
pull/4872/head
liangshiwei 6 years ago
committed by GitHub
parent
commit
0d426bcce0
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      docs/en/Blob-Storing-Aliyun.md
  2. 6
      docs/zh-Hans/Blob-Storing-Aliyun.md
  3. 21
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs
  4. 4
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs
  5. 7
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunTemporaryCredentialsCacheItem.cs
  6. 104
      framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/DefaultOssClientFactory.cs
  7. 4
      framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Volo/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestModule.cs

8
docs/en/Blob-Storing-Aliyun.md

@ -45,17 +45,19 @@ Configure<AbpBlobStoringOptions>(options =>
* **AccessKeyId** ([NotNull]string): AccessKey is the key to access the Alibaba Cloud API. It has full permissions for the account. Please keep it safe! Recommend to follow [Alibaba Cloud security best practicess](https://help.aliyun.com/document_detail/102600.html),Use RAM sub-user AccessKey to call API.
* **AccessKeySecret** ([NotNull]string): Same as above.
* **Endpoint** ([NotNull]string): Endpoint is the external domain name of OSS. See the [document](https://help.aliyun.com/document_detail/31837.html) for details.
* **Endpoint** ([NotNull]string): Endpoint is the external domain name of OSS. See the [document](https://help.aliyun.com/document_detail/31837.html) for details.
* **UseSecurityTokenService** (bool): Use [STS temporary credentials](https://help.aliyun.com/document_detail/100624.html) to access OSS services,default: `false`.
* **RegionId** (string): Access address of STS service. See the [document](https://help.aliyun.com/document_detail/66053.html) for details.
* **RoleArn** ([NotNull]string): STS required role ARN. See the [document](https://help.aliyun.com/document_detail/100624.html) for details.
* **RoleSessionName** ([NotNull]string): Used to identify the temporary access credentials, it is recommended to use different application users to distinguish.
* **Policy** (string): Additional permission restrictions. See the [document](https://help.aliyun.com/document_detail/100680.html) for details.
* **DurationSeconds** (int): Validity period(s) of a temporary access certificate,minimum is 900 and the maximum is 3600. **note**: Using subaccounts operated OSS,if the value is 0.
* **DurationSeconds** (int): Validity period(s) of a temporary access certificate,minimum is 900 and the maximum is 3600.
* **ContainerName** (string): You can specify the container name in Aliyun. If this is not specified, it uses the name of the BLOB container defined with the `BlogContainerName` attribute (see the [BLOB storing document](Blob-Storing.md)). Please note that Aliyun has some **rules for naming containers**. A container name must be a valid DNS name, conforming to the [following naming rules](https://help.aliyun.com/knowledge_detail/39668.html):
* Container names must start or end with a letter or number, and can contain only letters, numbers, and the dash (-) character.
* Container names Must start and end with lowercase letters and numbers.
* Container names must be from **3** through **63** characters long.
* **CreateContainerIfNotExists** (bool): Default value is `false`, If a container does not exist in Aliyun, `AliyunBlobProvider` will try to create it.
* **TemporaryCredentialsCacheKey** (bool): The cache key of STS credentials.
## Aliyun Blob Name Calculator
@ -70,4 +72,4 @@ Aliyun Blob Provider organizes BLOB name and implements some conventions. The fu
* `AliyunBlobProvider` is the main service that implements the Aliyun BLOB storage provider, if you want to override/replace it via [dependency injection](Dependency-Injection.md) (don't replace `IBlobProvider` interface, but replace `AliyunBlobProvider` class).
* `IAliyunBlobNameCalculator` is used to calculate the full BLOB name (that is explained above). It is implemented by the `DefaultAliyunBlobNameCalculator` by default.
* `IOssClientFactory` is used create OSS client. It is implemented by the `DefaultOssClientFactory` by default. You can override/replace it,if you want customize.
* `IOssClientFactory` is used create OSS client. It is implemented by the `DefaultOssClientFactory` by default. You can override/replace it,if you want customize.

6
docs/zh-Hans/Blob-Storing-Aliyun.md

@ -46,16 +46,18 @@ Configure<AbpBlobStoringOptions>(options =>
* **AccessKeyId** ([NotNull]string): 云账号AccessKey是访问阿里云API的密钥,具有该账户完全的权限,请你务必妥善保管!强烈建议遵循[阿里云安全最佳实践](https://help.aliyun.com/document_detail/102600.html),使用RAM子用户AccessKey来进行API调用.
* **AccessKeySecret** ([NotNull]string): 同上.
* **Endpoint** ([NotNull]string): Endpoint表示OSS对外服务的访问域名. [访问域名和数据中心](https://help.aliyun.com/document_detail/31837.html)
* **UseSecurityTokenService** (bool): 是否使用STS临时授权访问OSS,默认false. [STS临时授权访问OSS](https://help.aliyun.com/document_detail/100624.html)
* **RegionId** (string): STS服务的接入地址,每个地址的功能都相同,请尽量在同地域进行调用. [接入地址](https://help.aliyun.com/document_detail/66053.html)
* **RoleArn** ([NotNull]string): STS所需角色ARN. [STS临时授权访问OSS](https://help.aliyun.com/document_detail/100624.html)
* **RoleArn** ([NotNull]string): STS所需角色ARN.
* **RoleSessionName** ([NotNull]string): 用来标识临时访问凭证的名称,建议使用不同的应用程序用户来区分.
* **Policy** (string): 在扮演角色的时候额外添加的权限限制. 请参见[基于RAM Policy的权限控制](https://help.aliyun.com/document_detail/100680.html).
* **DurationSeconds** (int): 设置临时访问凭证的有效期,单位是s,最小为900,最大为3600. **注**:为0则使用子账号操作OSS.
* **DurationSeconds** (int): 设置临时访问凭证的有效期,单位是s,最小为900,最大为3600.
* **ContainerName** (string): 你可以在aliyun中指定容器名称. 如果没有指定它将使用 `BlogContainerName` 属性定义的BLOB容器的名称(请参阅[BLOB存储文档](Blob-Storing.md)). 请注意Aliyun有一些**命名容器的规则**,容器名称必须是有效的DNS名称,[符合以下命名规则](https://help.aliyun.com/knowledge_detail/39668.html):
* 只能包含小写字母,数字和短横线(-)
* 必须以小写字母和数字开头和结尾
* Bucket名称的长度限制在**3**到**63**个字符之间
* **CreateContainerIfNotExists** (bool): 默认值为 `false`, 如果aliyun中不存在容器, `AliyunBlobProvider` 将尝试创建它.
* **TemporaryCredentialsCacheKey** (bool): STS凭证缓存Key,默认Guid.NewGuid().ToString("N").
## Aliyun BLOB 名称计算器

21
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfiguration.cs

@ -25,6 +25,12 @@ namespace Volo.Abp.BlobStoring.Aliyun
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.Endpoint, Check.NotNullOrWhiteSpace(value, nameof(value)));
}
public bool UseSecurityTokenService
{
get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.UseSecurityTokenService, false);
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.UseSecurityTokenService, value);
}
public string RegionId
{
get => _containerConfiguration.GetConfiguration<string>(AliyunBlobProviderConfigurationNames.RegionId);
@ -88,18 +94,19 @@ namespace Volo.Abp.BlobStoring.Aliyun
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.CreateContainerIfNotExists, value);
}
private readonly BlobContainerConfiguration _containerConfiguration;
public AliyunBlobProviderConfiguration(BlobContainerConfiguration containerConfiguration)
private readonly string _temporaryCredentialsCacheKey;
public string TemporaryCredentialsCacheKey
{
_containerConfiguration = containerConfiguration;
get => _containerConfiguration.GetConfigurationOrDefault(AliyunBlobProviderConfigurationNames.TemporaryCredentialsCacheKey, _temporaryCredentialsCacheKey);
set => _containerConfiguration.SetConfiguration(AliyunBlobProviderConfigurationNames.TemporaryCredentialsCacheKey, value);
}
private readonly BlobContainerConfiguration _containerConfiguration;
public string ToKeyString()
public AliyunBlobProviderConfiguration(BlobContainerConfiguration containerConfiguration)
{
Uri uPoint = new Uri(Endpoint);
return $"blobstoring:aliyun:id:{AccessKeyId},sec:{AccessKeySecret},ept:{uPoint.Host.ToLower()},rid:{RegionId},ra:{RoleArn},rsn:{RoleSessionName},pl:{Policy}";
_containerConfiguration = containerConfiguration;
_temporaryCredentialsCacheKey = Guid.NewGuid().ToString("N");
}
}
}

4
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunBlobProviderConfigurationNames.cs

@ -5,12 +5,14 @@
public const string AccessKeyId = "Aliyun.AccessKeyId";
public const string AccessKeySecret = "Aliyun.AccessKeySecret";
public const string Endpoint = "Aliyun.Endpoint";
public const string UseSecurityTokenService = "Aliyun.UseSecurityTokenService";
public const string RegionId = "Aliyun.RegionId";
public const string RoleArn = "Aliyun.RoleArn";
public const string RoleSessionName = "Aliyun.RoleSessionName";
public const string DurationSeconds = "Aliyun.DurationSeconds";
public const string Policy = "Aliyun.Policy";
public const string ContainerName = "Aliyun:ContainerName";
public const string ContainerName = "Aliyun.ContainerName";
public const string CreateContainerIfNotExists = "Aliyun.CreateContainerIfNotExists";
public const string TemporaryCredentialsCacheKey = "Aliyun.TemporaryCredentialsCacheKey";
}
}

7
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AssumeRoleCredentialsCacheItem.cs → framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/AliyunTemporaryCredentialsCacheItem.cs

@ -6,8 +6,7 @@ using Volo.Abp.Caching;
namespace Volo.Abp.BlobStoring.Aliyun
{
[Serializable]
[CacheName("AssumeRoleCredentials")]
public class AssumeRoleCredentialsCacheItem
public class AliyunTemporaryCredentialsCacheItem
{
public string AccessKeyId { get; set; }
@ -15,12 +14,12 @@ namespace Volo.Abp.BlobStoring.Aliyun
public string SecurityToken { get; set; }
public AssumeRoleCredentialsCacheItem()
public AliyunTemporaryCredentialsCacheItem()
{
}
public AssumeRoleCredentialsCacheItem(string accessKeyId,string accessKeySecret,string securityToken)
public AliyunTemporaryCredentialsCacheItem(string accessKeyId,string accessKeySecret,string securityToken)
{
AccessKeyId = accessKeyId;
AccessKeySecret = accessKeySecret;

104
framework/src/Volo.Abp.BlobStoring.Aliyun/Volo/Abp/BlobStoring/Aliyun/DefaultOssClientFactory.cs

@ -6,8 +6,11 @@ using Aliyun.OSS;
using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Security.Encryption;
using static Aliyun.Acs.Core.Auth.Sts.AssumeRoleResponse;
namespace Volo.Abp.BlobStoring.Aliyun
{
@ -16,53 +19,82 @@ namespace Volo.Abp.BlobStoring.Aliyun
/// </summary>
public class DefaultOssClientFactory : IOssClientFactory, ITransientDependency
{
protected IDistributedCache<AssumeRoleCredentialsCacheItem> Cache { get; }
protected IDistributedCache<AliyunTemporaryCredentialsCacheItem> Cache { get; }
protected IStringEncryptionService StringEncryptionService { get; }
public DefaultOssClientFactory(
IDistributedCache<AssumeRoleCredentialsCacheItem> cache)
IDistributedCache<AliyunTemporaryCredentialsCacheItem> cache,
IStringEncryptionService stringEncryptionService)
{
Cache = cache;
StringEncryptionService = stringEncryptionService;
}
public virtual IOss Create(AliyunBlobProviderConfiguration aliyunConfig)
public virtual IOss Create(AliyunBlobProviderConfiguration configuration)
{
//Sub-account
if (aliyunConfig.DurationSeconds <= 0)
Check.NotNullOrWhiteSpace(configuration.AccessKeyId, nameof(configuration.AccessKeyId));
Check.NotNullOrWhiteSpace(configuration.AccessKeySecret, nameof(configuration.AccessKeySecret));
Check.NotNullOrWhiteSpace(configuration.Endpoint, nameof(configuration.Endpoint));
if (configuration.UseSecurityTokenService)
{
return new OssClient(aliyunConfig.Endpoint, aliyunConfig.AccessKeyId, aliyunConfig.AccessKeySecret);
//STS temporary authorization to access OSS
return GetSecurityTokenClient(configuration);
}
else
//Sub-account
return new OssClient(configuration.Endpoint, configuration.AccessKeyId, configuration.AccessKeySecret);
}
protected virtual IOss GetSecurityTokenClient(AliyunBlobProviderConfiguration configuration)
{
Check.NotNullOrWhiteSpace(configuration.RoleArn, nameof(configuration.RoleArn));
Check.NotNullOrWhiteSpace(configuration.RoleSessionName, nameof(configuration.RoleSessionName));
var cacheItem = Cache.Get(configuration.TemporaryCredentialsCacheKey);
if (cacheItem == null)
{
//STS temporary authorization to access OSS
var key = aliyunConfig.ToKeyString();
var cacheItem = Cache.Get(key);
if (cacheItem == null)
IClientProfile profile = DefaultProfile.GetProfile(
configuration.RegionId,
configuration.AccessKeyId,
configuration.AccessKeySecret);
DefaultAcsClient client = new DefaultAcsClient(profile);
AssumeRoleRequest request = new AssumeRoleRequest
{
IClientProfile profile = DefaultProfile.GetProfile(
aliyunConfig.RegionId,
aliyunConfig.AccessKeyId,
aliyunConfig.AccessKeySecret);
DefaultAcsClient client = new DefaultAcsClient(profile);
AssumeRoleRequest request = new AssumeRoleRequest
{
AcceptFormat = FormatType.JSON,
//eg:acs:ram::$accountID:role/$roleName
RoleArn = aliyunConfig.RoleArn,
RoleSessionName = aliyunConfig.RoleSessionName,
//Set the validity period of the temporary access credential, the unit is s, the minimum is 900, and the maximum is 3600. default 3600
DurationSeconds = aliyunConfig.DurationSeconds,
//Set additional permission policy of Token; when acquiring Token, further reduce the permission of Token by setting an additional permission policy
Policy = aliyunConfig.Policy.IsNullOrEmpty() ? null : aliyunConfig.Policy,
};
var response = client.GetAcsResponse(request);
cacheItem = new AssumeRoleCredentialsCacheItem(response.Credentials.AccessKeyId, response.Credentials.AccessKeySecret, response.Credentials.SecurityToken);
Cache.Set(key, cacheItem, new DistributedCacheEntryOptions()
{
//Subtract 10 seconds of network request time.
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(aliyunConfig.DurationSeconds - 10)
});
}
return new OssClient(aliyunConfig.Endpoint, cacheItem.AccessKeyId, cacheItem.AccessKeySecret, cacheItem.SecurityToken);
AcceptFormat = FormatType.JSON,
//eg:acs:ram::$accountID:role/$roleName
RoleArn = configuration.RoleArn,
RoleSessionName = configuration.RoleSessionName,
//Set the validity period of the temporary access credential, the unit is s, the minimum is 900, and the maximum is 3600. default 3600
DurationSeconds = configuration.DurationSeconds,
//Set additional permission policy of Token; when acquiring Token, further reduce the permission of Token by setting an additional permission policy
Policy = configuration.Policy.IsNullOrEmpty() ? null : configuration.Policy,
};
var response = client.GetAcsResponse(request);
cacheItem = SetTemporaryCredentialsCache(configuration, response.Credentials);
}
return new OssClient(
configuration.Endpoint,
StringEncryptionService.Decrypt(cacheItem.AccessKeyId),
StringEncryptionService.Decrypt(cacheItem.AccessKeySecret),
StringEncryptionService.Decrypt(cacheItem.SecurityToken));
}
private AliyunTemporaryCredentialsCacheItem SetTemporaryCredentialsCache(
AliyunBlobProviderConfiguration configuration,
AssumeRole_Credentials credentials)
{
var temporaryCredentialsCache = new AliyunTemporaryCredentialsCacheItem(
StringEncryptionService.Encrypt(credentials.AccessKeyId),
StringEncryptionService.Encrypt(credentials.AccessKeySecret),
StringEncryptionService.Encrypt(credentials.SecurityToken));
Cache.Set(configuration.TemporaryCredentialsCacheKey, temporaryCredentialsCache,
new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(configuration.DurationSeconds - 10)
});
return temporaryCredentialsCache;
}
}
}

4
framework/test/Volo.Abp.BlobStoring.Aliyun.Tests/Volo/Abp/BlobStoring/Aliyun/AbpBlobStoringAliyunTestModule.cs

@ -50,14 +50,16 @@ namespace Volo.Abp.BlobStoring.Aliyun
aliyun.AccessKeySecret = accessKeySecret;
aliyun.Endpoint = endpoint;
//STS
aliyun.UseSecurityTokenService = true;
aliyun.RegionId = regionId;
aliyun.RoleArn = roleArn;
aliyun.RoleSessionName = Guid.NewGuid().ToString("N");
aliyun.DurationSeconds = 0;
aliyun.DurationSeconds = 900;
aliyun.Policy = String.Empty;
//Other
aliyun.CreateContainerIfNotExists = true;
aliyun.ContainerName = _randomContainerName;
aliyun.TemporaryCredentialsCacheKey = "297A96094D7048DBB2C28C3FDB20839A";
_configuration = aliyun;
});
});

Loading…
Cancel
Save