Sts 授权直传阿里云 OSS-.net core实现
2020-07-21 14:20:46 # .net

前言

磁盘怎么又满了?赶紧 快 打电话给运维扩容扩容扩容!这个问题已经是我入职新公司两个月来,第 3 次听到了。经过一通了解,事情原来是这样的。虽然我们使用了阿里云的 OSS 对象存储服务,但是为了不暴露 AccessKeyId 以及 AccessKeySecret 给客户端,所以全部是由客户端上传到我们的服务器,由我们服务器中转上传,其实只要上传完成删除相应的文件应该就不会引发磁盘空间不足的问题,奈何之前的精神小伙并没有干这一步,文件放磁盘上当备份用。由此引发思考中转上传是不是太麻烦了,直传 OSS 不香吗? 如何保证 AccessKeyId 以及 AccessKeySecret 的安全以及 Bucket 权限问题呢?这就是下面要讲的阿里云 OSS 上的 Sts 授权模式。

STS 临时授权访问 OSS

OSS 可以通过阿里云 STS(Security Token Service)进行临时授权访问。通过 STS,您可以为第三方应用或子用户(即用户身份由您自己管理的用户)颁发一个自定义时效和权限的访问凭证。

以上是官方原话,经过我的实践结合理论,可以得出:我们可以通过 STS 颁发一个临时的 AccessKeyId,AccessKeySecret,SecurityToken, 用户可以通过这3个访问凭证对 Oss 进行相应操作。在我们申请颁布访问凭证的时候,还可以设置对应的权限。

Coding

在使用下面测试前,请先完成 STS临时授权访问OSS 的配置

  • 安装 Nuget
1
2
3
dotnet add package aliyun-net-sdk-core
dotnet add package aliyun-net-sdk-sts
dotnet add package Aliyun.OSS.SDK.NetCore
  • 代码参考案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class Program
{
static void Main(string[] args)
{
var bucketName = "<your bucket>";
var accessKeyId = "<your accessKeyId>";
var accessKeySecret = "<your accessKeySecret>";
var endpoint = "<your endpint>";
var region = "<your region>";
var roleArn = "<your roleArn>"; // 通过阿里云RAM管理角色管理可以拿到
var roleSessionName = "xxx"; // 随机指定一个即可
var objectName = "test.txt";

IClientProfile profile =
DefaultProfile.GetProfile(region, accessKeyId, accessKeySecret);
DefaultAcsClient client = new DefaultAcsClient(profile);
AssumeRoleRequest request = new AssumeRoleRequest();
request.AcceptFormat = FormatType.JSON;
//指定角色ARN
request.RoleArn = roleArn;
request.RoleSessionName = roleSessionName;
request.DurationSeconds = 3600;
request.Policy = BuildPolicy(bucketName, "avatars"); // 配置对应的权限

AssumeRoleResponse response = client.GetAcsResponse(request);
Console.WriteLine("AccessKeyId: " + response.Credentials.AccessKeyId);
Console.WriteLine("AccessKeySecret: " + response.Credentials.AccessKeySecret);
Console.WriteLine("SecurityToken: " + response.Credentials.SecurityToken);
Console.WriteLine("Expiration: " + DateTime.Parse(response.Credentials.Expiration).ToLocalTime());


var ossClient = new OssClient(endpoint, response.Credentials.AccessKeyId,
response.Credentials.AccessKeySecret,
response.Credentials.SecurityToken);

try
{
byte[] binaryData = Encoding.ASCII.GetBytes("test");
MemoryStream requestContent = new MemoryStream(binaryData);
// 上传文件。
ossClient.PutObject(bucketName, $"{bucketName}/{objectName}", requestContent);
Console.WriteLine("Put object succeeded");
}
catch (Exception ex)
{
Console.WriteLine("Put object failed, {0}", ex.Message);
}
}

public static string BuildPolicy(string bucket, string dir)
{
return "{\n" +
" \"Version\": \"1\", \n" +
" \"Statement\": [\n" +
" {\n" +
" \"Action\": [\n" +
" \"oss:PutObject\"\n" +
" ], \n" +
" \"Resource\": [\n" +
$" \"acs:oss:*:*:{bucket}/{dir}/*\" \n" +
" ], \n" +
" \"Effect\": \"Allow\"\n" +
" }\n" +
" ]\n" +
"}";
}
}

可以修改 BuildPolicy 里面的 Json 动态配置,以上配置了客户端拿到访问凭据后,只能上传文件到指定目录,没有其他权限了。其次访问STS服务拿到的 AccessKeyIdAccessKeySecret 都是临时与我们阿里云RAM控制面板拿到的是不一样的。这样就无须担心我们 AccessKeyIdAccessKeySecret 泄露以及访问权限的问题。

End

服务端颁发授权凭证,客户端直传 OSS 应该是目前的最佳实践,后面再配合回调地址,可以更好的贴近实际场景。但是回调地址必须是公网可访问的,这里就没整了。直传 OSS 比之前中转节省时间,也不需要占用额外的服务器资源。