基本概念

  • 子账号

    根据阿里云的主账号创建的子账号,每个子账号拥有自己AccessKey,可以和阿里云主账号一样正常的完成有权限的操作。一般来说,这里的子账号可以理解为具有某种权限的用户,可以被认为是一个具有某些权限的操作发起者。

  • 角色(Role)

    表示某种操作权限的虚拟概念,但是没有独立的登录密码和AccessKey。子账号可以扮演角色,扮演角色的时候的权限是该角色自身的权限。

  • 授权策略(Policy)

    用来定义权限的规则,比如允许用户上传、播放。

子账号和角色可以类比为个人和其身份的关系,某人在公司的角色是员工,在家里的角色是父亲,在不同的场景扮演不同的角色,但是还是同一个人。在扮演不同的角色的时候也就拥有对应角色的权限。单独的员工或者父亲概念并不能作为一个操作的实体,只有有人扮演了之后才是一个完整的概念。这里还可以体现一个重要的概念,那就是角色可以被多个不同的个人同时扮演。完成角色扮演之后,该个人就自动拥有该角色的所有权限。

使用场景

之前章节只用到了RAM的子账号功能,这些子账号都是可以长期正常使用的,发生泄露之后如果无法及时解除权限的话会很危险。

您部署服务器生成STS临时AK,可以自定义过期时间并且指定复杂的策略来对不同的子账号进行限制,仅提供最小的权限。

创建子账号

  1. 登录RAM控制台
    说明 如果您之前没有使用过阿里云控制台,需要先开通服务。
  2. 进入用户管理页面,如下图所示。

  3. 单击页面的新建用户创建一个拥有和主账号一样完全访问VOD权限的子账号,记住要勾选为编程访问的选项。

  4. 生成该账号的AccessKey。
    说明 一定要在这一步保存下来用于后续的访问。
  5. 返回用户管理界面,这里显示账号已创建。创建完成之后,该子账号还是没有任何权限,单击右边的添加权限

  6. 给该账号授予AliyunSTSAssumeRoleAccess策略后,单击确认

创建角色

  1. 打开RAM控制台,选择新建RAM角色

  2. 在新建RAM角色页面,类型选择阿里云账号,云账号ID选择当前云账号,填写角色名称后单击确定

  3. 选择角色管理,找到刚创建的角色,单击添加权限

  4. 给角色加上AliyunVODFullAccess系统授权。
    说明 为控制风险,建议采用最小权限,如AliyunVODUploadAuth等。

Java代码示例

现在一切准备就绪,可以正式使用STS来授权访问了。

这里使用一个简单的STS的JAVA示例。具体的调用方法如下,更详细的参数解释可以参考STS API文档

package pop;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import com.aliyuncs.vod.model.v20170321.CreateUploadVideoRequest;
import com.aliyuncs.vod.model.v20170321.CreateUploadVideoResponse;

/**
 * @author jack
 * @date 2020/5/25
 */
public class TestStsService {

    public static void main(String[] args) {
        // 只有RAM用户(子账号)才能调用 AssumeRole 接口
        // 阿里云主账号的AccessKeys不能用于发起AssumeRole请求
        // 请首先在RAM控制台创建一个RAM用户,并为这个用户创建AccessKeys
        String accessKeyId = "<access-key-id>";
        String accessKeySecret = "<access-key-secret>";
        // AssumeRole API 请求参数: RoleArn, RoleSessionName, Policy, and DurationSeconds
        // RoleArn 需要在 RAM 控制台上获取
        String roleArn = "<role-arn>";
        // RoleSessionName 是临时Token的会话名称,自己指定用于标识你的用户,主要用于审计,或者用于区分Token颁发给谁
        // 但是注意RoleSessionName的长度和规则,不要有空格,只能有'-' '_' 字母和数字等字符
        // 具体规则请参考API文档中的格式要求
        String roleSessionName = "session-name";// 自定义即可
        // 定制你的policy
        String policy = "{\n" +
                "  \"Version\": \"1\",\n" +
                "  \"Statement\": [\n" +
                "    {\n" +
                "      \"Action\": \"vod:*\",\n" +
                "      \"Resource\": \"*\",\n" +
                "      \"Effect\": \"Allow\"\n" +
                "    }\n" +
                "  ]\n" +
                "}";
        try {
            AssumeRoleResponse response = assumeRole(accessKeyId, accessKeySecret, roleArn, roleSessionName, policy);
            System.out.println("Expiration: " + response.getCredentials().getExpiration());
            System.out.println("Access Key Id: " + response.getCredentials().getAccessKeyId());
            System.out.println("Access Key Secret: " + response.getCredentials().getAccessKeySecret());
            System.out.println("Security Token: " + response.getCredentials().getSecurityToken());
            System.out.println("RequestId: " + response.getRequestId());

            createUploadVideo(response.getCredentials().getAccessKeyId(), response.getCredentials().getAccessKeySecret(), response.getCredentials().getSecurityToken());
        } catch (ClientException e) {
            System.out.println("Failed to get a token.");
            System.out.println("Error code: " + e.getErrCode());
            System.out.println("Error message: " + e.getErrMsg());
        }
    }

    static AssumeRoleResponse assumeRole(String accessKeyId, String accessKeySecret, String roleArn, String roleSessionName, String policy) throws ClientException {
        try {
            //构造default profile(参数留空,无需添加Region ID)
            /*
            说明:当设置SysEndpoint为sts.aliyuncs.com时,regionId可填可不填;反之,regionId必填,根据使用的服务区域填写,例如:cn-shanghai
            详情参考STS各地域的Endpoint,请参见接入地址(https://help.aliyun.com/document_detail/66053.html?spm=a2c4g.11186623.2.16.1db87074dzvl3J#reference-sdg-3pv-xdb)。
             */
            IClientProfile profile = DefaultProfile.getProfile("", accessKeyId, accessKeySecret);
            //用profile构造client
            DefaultAcsClient client = new DefaultAcsClient(profile);
            // 创建一个 AssumeRoleRequest 并设置请求参数
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setSysEndpoint("sts.aliyuncs.com");
            request.setSysMethod(MethodType.POST);
            request.setRoleArn(roleArn);
            request.setRoleSessionName(roleSessionName);
            request.setPolicy(policy);
            // 发起请求,并得到response
            final AssumeRoleResponse response = client.getAcsResponse(request);
            return response;
        } catch (ClientException e) {
            throw e;
        }
    }

    static void createUploadVideo(String accessKeyId, String accessKeySecret, String token) {
        // 点播服务所在的Region,接入服务中心为上海,则填cn-shanghai
        String regionId = "cn-shanghai";
        IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
        DefaultAcsClient client = new DefaultAcsClient(profile);

        CreateUploadVideoRequest request = new CreateUploadVideoRequest();
        request.setSecurityToken(token);
        request.setTitle("t5");
        request.setFileName("D:\\TestVideo\\t4.mp4");
        request.setFileSize(10240L);

        try {
            CreateUploadVideoResponse response = client.getAcsResponse(request);
            System.out.println("CreateUploadVideoRequest, " + request.getUrl());
            System.out.println("CreateUploadVideoRequest, requestId:" + response.getRequestId());
            System.out.println("UploadAddress, " + response.getUploadAddress());
            System.out.println("UploadAuth, " + response.getUploadAuth());
            System.out.println("VideoId, " + response.getVideoId());
        } catch (ClientException e) {
            System.out.println("action, error:" + e);
            e.printStackTrace();
        }
    }
}
				
  • RoleArn表示的是需要扮演的角色ID,角色的ID可以在角色管理>基本信息中找到。
  • RoleSessionName是一个用来标示临时凭证的名称,一般来说建议使用不同的应用程序用户来区分。
  • Policy表示的是在扮演角色的时候额外加上的一个权限限制。
    说明
    • 这里需要解释一下Policy,这里传入的Policy是用来限制扮演角色之后的临时凭证的权限。最后临时凭证获得的权限是角色的权限和这里传入的Policy的交集。
    • 在扮演角色的时候传入Policy的原因是为了灵活性,比如只能现在使用CreateUploadVideo接口。
  • DurationSeconds指的是临时凭证的有效期,单位是s,最小为900,最大为3600。
  • id和secret表示的是需要扮演角色的子账号的AccessKey。

其它语言代码示例

STS 还提供了其它语言的代码示例,参考:

请下载和安装对应语言版本的STS SDK或直接调用AssumeRole接口。 角色和策略等的配置,请参考前文Java代码示例。