本文主要介绍如何配置阿里云的OSS、RAM访问控制,然后使用子账户直接颁发临时凭证,供前端javascript或者其他后端来操作我们的阿里云资源。
首先说下目前应用场景:我需要将一个网站的所有静态资源(图片、视频等)上传的阿里云存储,访问的时候减少服务器带宽压力,希望上传过程直接通过前端js来操作,不再通过后端服务器,那么我们需要为前端提供上传凭证,就需要后端程序提供一个api来供其他服务或者前端获取凭证,阿里云对权限这一块,做的很完善,主要是给子账户配置权限,在哪配,怎么配置,做的越完善肯定越复杂。
当然你也可以直接使用七牛云,更加简单 七牛云对象存储JS SDK使用录
一、首先我们要明白阿里云的RAM访问控制是如何运作的。

有几个概念需要明白:
子账户(用户):你的阿里云账号登录控制台,是最大最高权限的账号,那么里面有很多数据子系统,你可以创建其他子账户来给你的各种应用使用,总不能直接给总账户吧,和OA权限一样的,各司其职。
用户组:你可以理解成企业的部门,分配权限的时候,直接给部门分权限,那么这里面的所有人都有部门权限了。
RAM角色:这个就是权限的具体体现,权限就是一个功能一个功能的操作控制,代表了能不能操作,那么RAM角色就是把权限进行打包,然后关联到人或者用户组;比如你的OSS操作和ECS操作是分别给两个APP使用的权限,那么就可以创建两个RAM角色,将他们分别分给各司其职的子账户即可。
STS:这是阿里云用来给子账户颁发临时密钥的系统,有个AssumeRole接口,我们后端API给前端提供的信息就是通过这个接口来的。
二、如何配置RAM?
1、登录阿里云【控制台】,鼠标移动到头像上,就会看到【访问控制】,进入到控制访问主界面


2、点开【用户】,点击【创建用户】,创建一个OssAccount的子账户,然后访问我需要的接口访问,不需要登录控制台,所以选择【编程访问】,点击确定

看到用户信息的界面已经展示出来了,如下图。把这两个AccessKey记录一下,等哈用

3、我们来直接给这个账户添加权限,添加【AliyunOSSFullAccess】、【AliyunSTSAssumeRoleAccess】这两个权限,保存即可,子账户就建立好了。

4、点击【RAM角色管理】打开界面,准备创建角色信息,点击【创建RAM】角色,名为Ram



5、还是一样的,授权【AliyunOSSFullAccess】、【AliyunSTSAssumeRoleAccess】,这里点击角色ram名称,进入详情,看到ARN信息,记录下等哈用。

三、怎么配置OSS?
1、创建OSS,进入主控制台,点击【Bucket列表】,再点击【创建Bucket】

2、我取名为carsonyangblog,选择【华南1(深圳)】,读写权限选择【公共读取】,确定即可。
公共读是因为我们要对外访问,可能我的图片需要给别的域名下使用。

3、还需要配置授权策略和跨域,因为我们要让前端直接上传到我们的bucket中。

4、点击【Bucket授权策略】,再点击【新增授权】,选择【子账户】,授权选择【完全控制】,即可。

5、点击【跨域设置】,再点击【创建规则】,按下图设置。

到这里我们Oss配置完了。
四、开始写代码
我的前端界面是:http://127.0.0.1:5500/ossupload.html
我的后端API地址是:http://localhost:5000/weatherforecast
1、后端代码开始:.NET Core API配置如下:
添加引用:Aliyun.Acs.Core、Aliyun.Acs.Sts
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
/*
* STSRegionId: https://help.aliyun.com/document_detail/66053.html?spm=a2c4g.11186623.6.793.46f17069mFpq2G
* OSSRegion:https://help.aliyun.com/document_detail/31837.html?spm=a2c4g.11186623.2.14.19d0433bBFviGo#concept-zt4-cvy-5db
*/
"OSS": {
/*获取临时凭证的接口地址 STSRegionId: https://help.aliyun.com/document_detail/66053.html?spm=a2c4g.11186623.6.793.46f17069mFpq2G */
"STSRegionId": "cn-shenzhen",
"STSEndpoint": "sts.cn-shenzhen.aliyuncs.com",
/* 刚刚创建的子账户OssAccount和两个accesskey */
"RoleSessionName": "OssAccount@1287***********31.onaliyun.com",
"AccessKeyId": "LTAI4**********rwXmiywo",
"AccessKeySecret": "wmhdQ******************MGBpgQ",
/* 刚刚创建的ARM角色的ARN信息 */
"RoleArn": "acs:ram::1***********1:role/ram",
/* 刚刚创建的Oss名称 */
"Bucket": "carsonyangblog",
/* Oss访问地址,深圳的Bucket,就选择深圳的地址 OSSRegion:https://help.aliyun.com/document_detail/31837.html?spm=a2c4g.11186623.2.14.19d0433bBFviGo#concept-zt4-cvy-5db */
"OSSRegion": "oss-cn-shenzhen",
/* 公共访问的地址,结合前端的文件名,就可以直接访问上传的文件了。Bucket名+OssRegin地址+aliyuncs.com+文件名 */
"DoMain": "http://carsonyangblog.oss-cn-shenzhen.aliyuncs.com/"
}
}API代码如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AliOssDemoApi.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Aliyun.Acs.Core;
using Aliyun.Acs.Core.Profile;
using Aliyun.Acs.Core.Http;
using Aliyun.Acs.Sts.Model.V20150401;
using Microsoft.AspNetCore.Cors;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
namespace AliOssDemoApi.Controllers
{
[EnableCors("CorsPolicy")]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly IOptions<OssConfig> _options;
private readonly ILogger<WeatherForecastController> _logger;
public static IMemoryCache _memoryCache = new MemoryCache(new MemoryCacheOptions());
public WeatherForecastController(IOptions<OssConfig> options, ILogger<WeatherForecastController> logger)
{
_options = options;
_logger = logger;
}
[HttpGet]
public OssTokenResult Get()
{
string cachekey = "OssToken";
OssTokenResult data = _memoryCache.Get<OssTokenResult>(cachekey);
if (data != null)
{
return data;
}
string REGIONID = _options.Value.STSRegionId;
string ENDPOINT = _options.Value.STSEndpoint;
//构建一个阿里云client,用于发起请求
//构建阿里云client时需要设置AccessKey ID和AccessKey Secret
DefaultProfile.AddEndpoint(REGIONID, REGIONID, "Sts", ENDPOINT);
IClientProfile profile = DefaultProfile.GetProfile(REGIONID, _options.Value.AccessKeyId, _options.Value.AccessKeySecret);
DefaultAcsClient client = new DefaultAcsClient(profile);
//构建AssumeRole请求
AssumeRoleRequest request = new AssumeRoleRequest();
request.AcceptFormat = FormatType.JSON;
//指定角色ARN
request.RoleArn = _options.Value.RoleArn;
request.RoleSessionName = _options.Value.RoleSessionName;
//设置Token有效期,可选参数,默认3600秒
request.DurationSeconds = 3600;
//设置Token的附加权限策略;在获取Token时,通过额外设置一个权限策略进一步减小Token的权限
//request.Policy="<policy-content>"
try
{
AssumeRoleResponse response = client.GetAcsResponse(request);
Console.WriteLine("AccessKeyId: " + response.Credentials.AccessKeyId);
Console.WriteLine("AccessKeySecret: " + response.Credentials.AccessKeySecret);
Console.WriteLine("SecurityToken: " + response.Credentials.SecurityToken);
//Token过期时间;服务器返回UTC时间,这里转换成北京时间显示
Console.WriteLine("Expiration: " + DateTime.Parse(response.Credentials.Expiration).ToLocalTime());
data = new OssTokenResult();
data.AccessKeyId = response.Credentials.AccessKeyId;
data.AccessKeySecret = response.Credentials.AccessKeySecret;
data.StsToken = response.Credentials.SecurityToken;
data.Region = _options.Value.OSSRegion;
data.Bucket = _options.Value.Bucket;
data.DoMain = _options.Value.DoMain;
_memoryCache.Set(cachekey, data, new MemoryCacheEntryOptions().SetAbsoluteExpiration(DateTime.Parse(response.Credentials.Expiration).ToLocalTime()));
return data;
}
catch (Exception ex)
{
_logger.LogError(ex, "获取凭证出错");
_memoryCache.Remove(cachekey);
return new OssTokenResult();
}
}
}
}OSsConfig.cs结构
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AliOssDemoApi.Model
{
public class OssConfig
{
public string STSRegionId { get; set; }
public string STSEndpoint { get; set; }
public string AccessKeyId { get; set; }
public string AccessKeySecret { get; set; }
public string RoleArn { get; set; }
public string RoleSessionName { get; set; }
public string Bucket { get; set; }
public string OSSRegion { get; set; }
public string DoMain { get; set; }
}
}OssTokenResult.cs结构
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AliOssDemoApi.Model
{
public class OssTokenResult
{
public string AccessKeyId { get; set; }
public string AccessKeySecret { get; set; }
public string StsToken { get; set; }
public string Region { get; set; }
public string Bucket { get; set; }
public string DoMain { get; set; }
}
}API跨域设置
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<OssConfig>(Configuration.GetSection("OSS"));
services.AddCors(options => options.AddPolicy("CorsPolicy",
builder =>
{
//不限制
//builder.AllowAnyMethod()
// .SetIsOriginAllowed(_ => true)
// .AllowAnyHeader()
// .AllowCredentials();
//限制
builder.AllowAnyMethod()
.WithOrigins(new[] { "http://127.0.0.1:5500" })
.AllowAnyHeader()
.AllowCredentials();
}));
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseCors("CorsPolicy");
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
} 2、前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="jquery.js"></script>
<script src="http://gosspublic.alicdn.com/aliyun-oss-sdk-6.8.0.min.js"></script>
</head>
<body>
<body>
<input type="file" id="file" />
<img src="" id="imgsrc">
<script type="text/javascript">
document.getElementById('file').addEventListener('change', function (e) {
let file = e.target.files[0];
let storeAs = 'upload-file123.png';//自定义文件名
let domain = '';//后台返回的文件访问域名 两个合起来就是文件访问全路径
console.log(file.name + ' => ' + storeAs);
// OSS.urlib是SDK内部封装的发送请求的逻辑,开发者可以使用任何发送请求的库向sts-server发送请求。
OSS.urllib.request("http://localhost:5000/weatherforecast", { method: 'GET' }, (err, response) => {
if (err) {
return alert(err);
}
try {
result = JSON.parse(response);
} catch (e) {
return alert('parse sts response info error: ' + e.message);
}
domain = result.doMain;
let client = new OSS({
accessKeyId: result.accessKeyId,
accessKeySecret: result.accessKeySecret,
stsToken: result.stsToken,
region: result.region,
bucket: result.bucket
});
// storeAs可以自定义为文件名(例如file.txt)或目录(例如abc/test/file.txt)的形式,实现将文件上传至当前Bucket或Bucket下的指定目录。
// file可以自定义为File对象、Blob数据以及OSS Buffer。
client.multipartUpload(storeAs, file).then(function (result) {
console.log(result);
$("#imgsrc").attr("src", domain + storeAs)
}).catch(function (err) {
console.log(err);
});
});
});
</script>
</body>
</body>
</html>
川公网安备 51010702003150号
留下您的脚步
最近评论