关于阿里云OSS资源STS访问控制

目前还在看
什么是STS
AssumeRole
RAM角色和STS Token常见问题
RAM Policy常见示例
使用TST临时访问凭证访问OSS
大佬的博文1
大佬的博文2
做一下记录,稍后来补.。。。。。
最终解决,生成token这里
最终解决,读取这里
明天再来补自己的笔记;

先说说这个东西用在OSS解决了什么:

1:前端或者其他用户需要临时操作oss
2:私有资源指向在指定时间内允许访问


准备:

1,一个设置为私有的oss-bucket

在这里插入图片描述


2.一个专门用于STSToken相关操作的RAM账号

在这里插入图片描述


3.获取这个用户的AKID和AS

在这里插入图片描述
AS只在第一次打开的时候会显示,记得保存


4.创建权限策略

在这里插入图片描述

{
  "Version": "1",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "oss:GetObject",
        "oss:PutObject",
        "oss:DeleteObject",
        "oss:ListParts",
        "oss:AbortMultipartUpload",
        "oss:ListObjects"
      ],
      "Resource": [
        "acs:oss:*:*:xxxx/xxx"
      ],
      "Condition": {}
    }
  ]
}

授权角色拥有oss获取权限,允许操作的资源是one-goods的bucket,下面/goodsimg目录下的文件
buket名称/目录/*,代表可以操作目录之下所有文件,单独使用目录是无效的

{
  "Version": "1",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "oss:GetObject",
      "Resource": "acs:oss:*:*:one-goods/goodsimg/*"
    }
  ]
}

5.创建/编辑角色

创建:
创建角色-》信任实体:阿里云账号-》下一步-》确定
编辑:
在这里插入图片描述
角色是为了一会STS创建token 的时候指定角色,方便给token指定授权,而不是给当前创建的RAM用户使用,记得复制这里的RAN稍后靠这个指定角色
所以我们还需要给当前的RAM提供STS权限


6.为用户添加权限,这里主要是为了给用户添加STS权限,稍后当前ram才能签发token

在这里插入图片描述


至此,准备工作就完成了;

我们来代码部分;

这里我只示范资源访问,资源请求可以看我上面提供的大佬的博文。他们做了文件上传;
首先需要依赖:

<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-core</artifactId>
    <version>3.2.2</version>
</dependency>
<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>aliyun-java-sdk-sts</artifactId>
    <version>3.0.0</version>
</dependency>
<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
	<version>3.11.3</version>
</dependency>

有奇怪的现象是依赖有时候在dependencyManageMent里不下载,拖到普通的dependencys里下了再拉回管理来吧

直接上代码,一行一注释,大家慢慢看

package com.doria.pzh.core;

import cn.hutool.core.bean.BeanUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import java.net.URL;
import java.util.Date;
import java.util.Random;

@SpringBootTest
@RunWith(SpringRunner.class)
public class TestSrv {
    @Autowired
    RedisTemplate<String, String> redisTemplate;

    private final String stsAk="LTAaxxxxxxxxsrkDYw5";
    private final String stsAs="QFeeQCI1xxxxxxxxxxxxxHxG";

    @Test
    public void test(){
        STSResponse sts = sts();
        OssDownVO ossDownVO = BeanUtil.copyProperties(sts, OssDownVO.class);
        ossDownVO.setBucketName("oxxxx"); // ossbucket名称
        ossDownVO.setOssEndpoint("oss-cn-beijing.aliyuncs.com");
        // 注意根目录不要带[/],根目录下的就直接写文件名否则报错The specified key does not exist
        ossDownVO.setResourceOssPath("新建文本文档.txt"); // 资源路径
        URL down = down(ossDownVO);
        // 打印获取到的url
        System.out.println(down);
    }

    /**
     * 获取STS凭证。
     * @return
     */
    public STSResponse sts() {
        AssumeRoleResponse.Credentials credentials = null;
        String endpoint = "sts.cn-beijing.aliyuncs.com"; // STS服务的节点
        String accessKeyId = stsAk;  // 阿里的AK(不是那个ak)
        String accessKeySecret = stsAs; // AS
        // 角色名称,点开角色能看到,这里决定了我们授权的临时token具有什么角色,而角色又有具体的权限
        String roleArn = "acs:ram::1133899369190070:role/oxls-crud";
        String roleSessionName = "AliyunDMSRol--ePolicy"+new Random().nextInt(10000); // 看样子是会话名称的意思
        // 这段可以根据情况自己决定设不设置,这个的作用是在设置的时候是否在原来角色的基础之上额外添加权限策略
        /*String policy = "{\n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:GetObject\",\n" +
                "                \"oss:PutObject\",\n" +
                "                \"oss:DeleteObject\",\n" +
                "                \"oss:ListParts\",\n" +
                "                \"oss:AbortMultipartUpload\",\n" +
                "                \"oss:ListObjects\"\n" +
                "            ],\n" +
                "            \"Effect\": \"Allow\",\n" +
                "            \"Resource\": [\n" +
                "               \"acs:oss:*:*:oxls/course/*\",\n" +
                "               \"acs:oss:*:*:oxls/course\",\n" +
                "               \"acs:oss:*:*:oxls/*\",\n" +
                "               \"acs:oss:*:*:oxls/\"\n" +
                "            ]\n" +
                "        }\n" +
                "    ],\n" +
                "    \"Version\": \"1\"\n" +
                "}";*/
        try {
            // 创建一个 Aliyun Acs Client, 用于发起 OpenAPI 请求
            // 添加endpoint(直接使用STS endpoint,前两个参数留空,无需添加region ID)
            DefaultProfile.addEndpoint("", "", "Sts", endpoint);
            // 构造default profile(参数留空,无需添加region ID),客户端描述文件
            IClientProfile profile = DefaultProfile.getProfile("", accessKeyId, accessKeySecret);
            // 用profile构造client,至此就拥有了客户端
            DefaultAcsClient client = new DefaultAcsClient(profile);
            // 创建一个 AssumeRoleRequest 并设置请求参数,一个扮演某个角色的请求
            final AssumeRoleRequest request = new AssumeRoleRequest();
            request.setMethod(MethodType.POST); // 请求类型
            request.setRoleArn(roleArn); // 设置角色ARN
            request.setDurationSeconds(900L);// 设置过期时间,最小值15min也就是900秒,不设置默认3600
            request.setRoleSessionName(roleSessionName); //设置会话名称,这里可以自定义,仅仅为了区别token分发给了谁
            //request.setPolicy(policy); // 可选,如果设置了就需要添加
            request.setProtocol(ProtocolType.HTTPS); // 必须使用HTTPS协议访问STS服务);
            final AssumeRoleResponse response = client.getAcsResponse(request); // 使用客户端执行请求
            credentials = response.getCredentials(); // 获取凭证
            // 这里可以再封装返回,或者自行用这些参数请求服务获取正确的url以后返回,也可以获取url后直接重定向,总之就看你自己拉
            System.out.println("Expiration: " + credentials.getExpiration()); // 获取过期时间
            System.out.println("Access Key Id: " + credentials.getAccessKeyId());// 获取AK
            System.out.println("Access Key Secret: " + credentials.getAccessKeySecret());// 获取AS
            System.out.println("Security Token: " + credentials.getSecurityToken());// 获取安全token
            System.out.println("RequestId: " + response.getRequestId());// 获取请求id
        } catch (ClientException e) {
            System.out.println("Failed:");
            System.out.println("Error code: " + e.getErrCode());
            System.out.println("Error message: " + e.getErrMsg());
            System.out.println("RequestId: " + e.getRequestId());
        }
        if (ObjectUtils.isNotEmpty(credentials))
            return STSResponse.builder().accessKeyId(credentials.getAccessKeyId())
                    .accessKeySecret(credentials.getAccessKeySecret())
                    .endpoint(endpoint)
                    .expiration(credentials.getExpiration())
                    .securityToken(credentials.getSecurityToken())
                    .build();
        return new STSResponse();
    }

    /*
     * 下载文件
     *
     * @param ossDownVO 下载文件实体
     * @return 文件的oss地址,不含http/https
     */
    public static URL down(OssDownVO ossDownVO) {
        // String endpoint = stsResponse.getEndpoint(); // 指定节点名称
        String accessKeyId = ossDownVO.getAccessKeyId(); // 指定AK(STS获取到的AK)
        String accessKeySecret = ossDownVO.getAccessKeySecret();// 指定AS(STS获取到的AS)
        String securityToken = ossDownVO.getSecurityToken();// 指定安全Token(STS获取到的安全token)
        String bucketName = ossDownVO.getBucketName(); // bucket名称
        String ossEndpoint = ossDownVO.getOssEndpoint();// OSS节点名称
        String ossPath = ossDownVO.getResourceOssPath();// 资源路径省略节点和bucket部分

        // 指定oss节点名称,AK,AS,ST
        OSS ossClient = new OSSClientBuilder().build(ossEndpoint, accessKeyId, accessKeySecret, securityToken);
        // 设置过期时间,上面设置的是我们获取到的token过期时间,这里设置的是资源过期时间
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
        // 计算获取资源路径
        URL url = ossClient.generatePresignedUrl(bucketName, ossPath, expiration);
        // 关流
        ossClient.shutdown();
        return url;
    }

}

实体

// 下载文件请求VO
@Data
@AllArgsConstructor
@NoArgsConstructor
public class OssDownVO {
    private String expiration;
    private String accessKeyId;
    private String accessKeySecret;
    private String securityToken;
    private String requestId;
    private String bucketName;
    private String ossEndpoint;
    private String resourceOssPath;
}
// STS 获取到的响应结果
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class STSResponse {
    private String endpoint;
    private String expiration;
    private String accessKeyId;
    private String accessKeySecret;
    private String securityToken;
    private String requestId;
}

总结一波

用户

用于细化管理每个子账号的权限,可以设置只能使用api或者控制台登录
在这里插入图片描述
在这里插入图片描述
里面可以使用系统设置好的权限,也可以自定义权限策略


策略

在这里插入图片描述
用于设置一个权限或者权限组和,这个权限可以给其他用户直接使用,也可以把权限给某个角色

角色

在这里插入图片描述
角色为一个权限的集合,可以给角色设置各种权限,也可以使用自定义的权限策略,通过角色的RAN就可以动态的生成临时访问Token,使用赋予角色的权限

用户组

在这里插入图片描述
用户组其实就是在批量赋予权限,具体权限的编辑和角色与用户一样

实际使用

/**
 * 阿里云STS访问控制工具
 */
@Service
public class AliYunSTSUtils {

    private static STSCertificate stsCertificate;
    @Value("${stsEndpoint}")
    private String stsEndpoint;
    @Value("${stsRoleArn}")
    private String stsRoleArn;
    @Value("${downloadUrlExp}")
    private Long downloadUrlExp;
    @Autowired
    private AliyunOSSConfig aliyunConfig; //已经配置好的oss配置类bean,内含节点信息和桶名称

    /**
     * 根据oss资源路径获取授权以后的临时下载链接
     *
     * @param ossPath
     * @return
     * @throws ClientException
     */
    public URL getPrivateOssResourse(String ossPath) throws ClientException, MalformedURLException {
        if (StringUtils.isBlank(ossPath))
            return new URL("");
        // 示例:https://asssua.oss-cn-shenzhen.aliyuncs.com/audioCourse/NEVERNEVER%20-%20Glorious.mp3
        // 去除前缀获得OSS资源路径
        ossPath = ossPath.replace(aliyunConfig.getPrivateUrlPrefix(), "");
        if (ObjectUtils.isEmpty(stsCertificate) ||
                PzhTimeUtils.getMills(LocalDateTime.parse(stsCertificate.getExpiration(), DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'")),ZoneOffset.UTC) - System.currentTimeMillis() <= 60000
        ) {
            // 如果凭证为空或者距离过期小于1分钟,执行刷新凭证
            stsCertificate = getStsCertificate();
        }
        STSOssDownVO stsOssDownVO = BeanUtil.copyProperties(stsCertificate, STSOssDownVO.class);
        stsOssDownVO.setBucketName(aliyunConfig.getPrivateBucketName());
        stsOssDownVO.setOssEndpoint(aliyunConfig.getPrivateEndpoint());
        stsOssDownVO.setResourceOssPath(ossPath);
        return getDownLoadUrl(stsOssDownVO);
    }

    // 获取STS凭证,凭证代表了当前对象客户端通过了授权,这个授权在过期之前可以一直执行oss的相对操作
    private STSCertificate getStsCertificate() throws ClientException {
        AssumeRoleResponse.Credentials credentials;
        String endpoint = stsEndpoint; // STS服务的节点
        String accessKeyId = aliyunConfig.getPrivateAccessKeyId();  // 阿里的AK(不是那个哒哒哒冒蓝火的ak)
        String accessKeySecret = aliyunConfig.getPrivateAccessKeySecret(); // AS
        // 角色名称,点开角色能看到,这里决定了我们授权的临时token具有什么角色,而角色又有具体的权限
        String roleArn = stsRoleArn;
        String roleSessionName = "AliyunDMSRol--ePolicy"; // 看样子是会话名称的意思
        // 这段可以根据情况自己决定设不设置,这个的作用是在设置的时候是否在原来角色的基础之上额外添加权限策略
        /*String policy = "{\n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:GetObject\",\n" +
                "                \"oss:PutObject\",\n" +
                "                \"oss:DeleteObject\",\n" +
                "                \"oss:ListParts\",\n" +
                "                \"oss:AbortMultipartUpload\",\n" +
                "                \"oss:ListObjects\"\n" +
                "            ],\n" +
                "            \"Effect\": \"Allow\",\n" +
                "            \"Resource\": [\n" +
                "               \"acs:oss:*:*:oxls/course/*\",\n" +
                "               \"acs:oss:*:*:oxls/course\",\n" +
                "               \"acs:oss:*:*:oxls/*\",\n" +
                "               \"acs:oss:*:*:oxls/\"\n" +
                "            ]\n" +
                "        }\n" +
                "    ],\n" +
                "    \"Version\": \"1\"\n" +
                "}";*/

        // 创建一个 Aliyun Acs Client, 用于发起 OpenAPI 请求
        // 添加endpoint(直接使用STS endpoint,前两个参数留空,无需添加region ID)
        DefaultProfile.addEndpoint("", "", "Sts", endpoint);
        // 构造default profile(参数留空,无需添加region ID),客户端描述文件
        IClientProfile profile = DefaultProfile.getProfile("", accessKeyId, accessKeySecret);
        // 用profile构造client,至此就拥有了客户端
        DefaultAcsClient client = new DefaultAcsClient(profile);
        // 创建一个 AssumeRoleRequest 并设置请求参数,一个扮演某个角色的请求
        final AssumeRoleRequest request = new AssumeRoleRequest();
        request.setMethod(MethodType.POST); // 请求类型
        request.setRoleArn(roleArn); // 设置角色ARLNL
        request.setDurationSeconds(3600L);// 设置过期时间,最小值15min也就是900秒,不设置默认3600
        request.setRoleSessionName(roleSessionName); //设置会话名称,这里可以自定义,仅仅为了区别token分发给了谁
        //request.setPolicy(policy); // 可选,如果设置了就需要添加
        request.setProtocol(ProtocolType.HTTPS); // 必须使用HTTPS协议访问STS服务);
        final AssumeRoleResponse response = client.getAcsResponse(request); // 使用客户端执行请求
        credentials = response.getCredentials(); // 获取凭证

        if (ObjectUtils.isNotEmpty(credentials))
            return STSCertificate.builder().accessKeyId(credentials.getAccessKeyId())
                    .accessKeySecret(credentials.getAccessKeySecret())
                    .endpoint(endpoint)
                    .expiration(credentials.getExpiration())
                    .securityToken(credentials.getSecurityToken())
                    .build();
        return new STSCertificate();
    }

    /**
     * 获取授权以后的下载链接
     *
     * @param ossDownVO 下载必备参数。包含了oss参数以及资源位置和证书
     * @return
     */
    private URL getDownLoadUrl(STSOssDownVO ossDownVO) {
        String accessKeyId = ossDownVO.getAccessKeyId(); // 指定AK(STS获取到的AK)
        String accessKeySecret = ossDownVO.getAccessKeySecret();// 指定AS(STS获取到的AS)
        String securityToken = ossDownVO.getSecurityToken();// 指定安全Token(STS获取到的安全token)
        String bucketName = ossDownVO.getBucketName(); // bucket名称
        String ossEndpoint = ossDownVO.getOssEndpoint();// OSS节点名称
        String ossPath = ossDownVO.getResourceOssPath();// 资源路径省略节点和bucket部分
        // 指定oss节点名称,AK,AS,ST
        OSS ossClient = new OSSClientBuilder().build(
                ossEndpoint,
                accessKeyId,
                accessKeySecret,
                securityToken);
        // 设置过期时间,上面设置的是我们获取到的token过期时间,这里设置的是资源过期时间
        Date expiration = new Date(System.currentTimeMillis() + downloadUrlExp * 1000);
        // 计算获取资源路径
        URL url = ossClient.generatePresignedUrl(bucketName, ossPath, expiration);
        // 关流
        ossClient.shutdown();
        return url;
    }
}

@ApiModel(value = "STS授权凭证-sts authorization certificate")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class STSCertificate {

    // sts节点
    private String endpoint;
    // 过期时间
    private String expiration;
    // 凭证ak
    private String accessKeyId;
    // 凭证as
    private String accessKeySecret;
    // 凭证token
    private String securityToken;
    // 请求id
    private String requestId;

}

报错提示:

com.aliyuncs.exceptions.ClientException: NoSuchBucket : The specified bucket does not exist.
千万记住STSEndpoint需要的是STS节点,而不是你的OSS节点
sts.cn-hangzhou.aliyuncs.com
sts.aliyuncs.com

权限不足的解决

com.aliyuncs.exceptions.ClientException: NoPermission : You are not authorized to do this action. You should be authorized by RAM.
https://blog.csdn.net/u014089832/article/details/118735933

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 访问阿里云OSS(对象存储服务)图片失败可能有多种原因。 首先,可能是由于网络连接问题导致无法访问阿里云OSS。在网络连接不稳定、慢或中断的情况下,访问OSS图片会失败。此时,可以尝试检查网络连接,并确保网络状况良好。 其次,可能是由于OSS对象不存在或被意外删除导致无法访问。在请求访问OSS图片时,如果对象不存在,将返回错误信息。此时,可以检查对象的路径和名称是否正确,并确保对象未被删除。 另外,可能是由于访问权限限制导致无法访问OSS图片。阿里云OSS提供了丰富的权限控制机制,可以通过私有、公共读、公共读写等权限设置来控制对象的访问。如果没有正确的权限设置,可能无法正常访问OSS图片。此时,可以检查访问对象的权限设置,并确保拥有足够的访问权限。 最后,可能是由于错误的请求方式或参数导致无法访问OSS图片。在请求OSS图片时,需要正确地使用API接口、请求方法和参数。如果请求方式或参数错误,阿里云OSS将无法正确处理请求并返回相应的图片。此时,可以检查请求方式和参数是否正确,并参考阿里云OSS API文档进行调整。 综上所述,访问阿里云OSS图片失败可能是由于网络连接问题、对象不存在、访问权限限制或错误的请求方式或参数等原因导致的。可以根据具体情况检查相关因素,并采取相应的措施来解决问题。 ### 回答2: 访问阿里云OSS图片失败可能是由于多种原因引起的。 首先,可能是由于网络连接问题导致无法访问OSS图片。这可能是由于网络连接不稳定、网络信号弱或者代理服务器的问题。建议检查网络连接,确认网络正常后再次尝试访问。 其次,可能是由于OSS图片的地址设置错误导致无法访问。检查图片的URL地址是否正确,确认是否包含了正确的域名、桶名和图片路径。 此外,还可能是由于权限设置不正确导致无法访问。在阿里云OSS中,需要正确设置桶的访问权限以及图片的访问权限。确保桶的读取权限设置为公共读或者授权用户有访问权限,并且图片的权限也正确配置。 最后,还可能是由于阿里云OSS服务端故障导致无法访问。在这种情况下,建议联系阿里云客服或者开发者支持团队,寻求帮助并报告问题,他们将会及时处理并解决问题。 综上所述,访问阿里云OSS图片失败可能是由于网络连接问题、URL地址设置错误、权限设置不正确或者服务端故障等原因引起的。根据具体情况,可以逐步排查并解决问题。 ### 回答3: 当访问阿里云OSS图片失败时,可能有以下几个原因: 1. 链接错误:请确保访问阿里云OSS的链接地址正确,包括域名、路径等信息是否填写正确。 2. 访问权限限制:在阿里云OSS中,每个存储桶都有自己的访问权限设置。请确保您拥有访问该图片的权限。 3. 存储桶设置问题:您需要确认存储桶是否处于正常状态。可能是存储桶已被删除、权限设置有误等情况导致无法访问。 4. 图片不存在:如果您输入的图片路径错误或者该图片已被删除,将导致访问失败。 5. 网络问题:可能是网络连接不稳定或者网络延迟导致无法正常访问阿里云OSS。此时,您可以尝试刷新页面或者稍后再试。 6. 阿里云OSS服务端故障:可能是阿里云OSS服务端出现故障导致无法正常访问。此时,您可以联系阿里云技术支持反馈问题,等待解决。 总结起来,访问阿里云OSS图片失败可能是链接错误、访问权限限制、存储桶设置问题、图片不存在、网络问题或阿里云OSS服务端故障等原因导致的。如果您遇到该问题,可以逐一排查以上原因,找到具体原因后采取相应的解决措施。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值