使用阿里云STS临时token完成阿里云OSS图片上传(Springboot+Vue)

本篇文章基于Springboot+Vue+Vant使用阿里云OSS图片上传功能,后端使用阿里云STS临时token安全认证。

准备工作

RAM相关

阿里云RAM官网:阿里云RAM官网
根据官网上的前四个步骤来操作 设置RAM子账号和自定义、配置权限和角色。

OSS相关

购买OSS服务

官网:阿里云OSS官网

创建一个oss bucket

创建名称和选择地区 这个地区的选择后面要用到
在这里插入图片描述

bucket权限控制

在这里插入图片描述

跨域设置

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

Springboot后端

工作原理:

在这里插入图片描述

所以我们只后端需要获取STS的凭证之后 前端拿到后端获取的STS凭证来上传阿里云图片

SDK官网下载

阿里云JAVASDK:阿里云JAVASDK官网

将sdk下载到本地 然后放到和pom文件夹同级目录下,可以去了解maven使用本地下载的sdk
在这里插入图片描述
在pom文件中加入:

  <!-- 阿里云 SDK -->
       <dependency>
			<groupId>com.aliyun.oss</groupId>
			<artifactId>aliyun-sdk-oss</artifactId>
			<version>2.8.3</version>
		</dependency>
		
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-sts</artifactId>
            <version>2.1.6</version>
            <scope>system</scope>
            <systemPath>${basedir}/lib/aliyun-java-sdk-sts-2.1.6.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.aliyun</groupId>
            <artifactId>aliyun-java-sdk-core</artifactId>
            <version>2.1.7</version>
            <scope>system</scope>
            <systemPath>${basedir}/lib/aliyun-java-sdk-core-2.1.7.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>net.sf.json-lib</groupId>
            <artifactId>json-lib</artifactId>
            <version>2.4</version>
            <scope>system</scope>
            <systemPath>${basedir}/lib/json-lib-2.4-jdk15.jar</systemPath>
        </dependency>

这个一定要打开 
		 <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <includeSystemScope>true</includeSystemScope>
                </configuration>
            </plugin>

STS获取

STSVO
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;


@ApiModel
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class STSVo {

    @ApiModelProperty("host")
    private String host;

    @ApiModelProperty("ossAccessKeyId")
    private String ossAccessKeyId;

    @ApiModelProperty("accessKeySecret")
    private String accessKeySecret;
    

    @ApiModelProperty("signature")
    private String signature;

    @ApiModelProperty("policy")
    private String policy;

    @ApiModelProperty("userPath")
    private String userPath;

    @ApiModelProperty("securityToken")
    private String securityToken;

}
AliyunSTSService(获取STS临时token)

官网第五步:阿里云STS临时token
这里对应官网的步骤五 对应的api数据看官网的如何获取 只需要替换如下代码中的
1、roleArn
2、getAccessKey
3、accessKeySecret
4、policy
5、getHost 你的oss地址
在这里插入图片描述

import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;

import com.aliyuncs.DefaultAcsClient;
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.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import com.google.gson.Gson;
import lombok.AllArgsConstructor;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimeZone;

@Service
@AllArgsConstructor
public class AliyunSTSService {



	/**
	 * 
	 */
	// 目前只有"cn-shanghai"这个region可用, 不要使用填写其他region的值
	public static final String REGION_CN_BEIJING = "cn-beijing";
	public static final String ENDPOINT = "sts.cn-beijing.aliyuncs.com";
	public static final String STS_API_VERSION = "2015-04-01";
	protected AssumeRoleResponse assumeRole(String accessKeyId, String accessKeySecret, String roleArn,
			String roleSessionName, String policy, ProtocolType protocolType, long durationSeconds) throws ClientException 
	{
		try {
			
			DefaultProfile.addEndpoint("",REGION_CN_BEIJING, "Sts", ENDPOINT);;
			// 创建一个 Aliyun Acs Client, 用于发起 OpenAPI 请求
			IClientProfile profile = DefaultProfile.getProfile(REGION_CN_BEIJING, accessKeyId, accessKeySecret);
			DefaultAcsClient client = new DefaultAcsClient(profile);

			// 创建一个 AssumeRoleRequest 并设置请求参数
			final AssumeRoleRequest request = new AssumeRoleRequest();
			request.setVersion(STS_API_VERSION);
			request.setMethod(MethodType.POST);
			request.setProtocol(protocolType);

			request.setRoleArn(roleArn);
			request.setRoleSessionName(roleSessionName);
			request.setPolicy(policy);
			request.setDurationSeconds(durationSeconds);

			// 发起请求,并得到response
			final AssumeRoleResponse response = client.getAcsResponse(request);

			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());

			return response;
		} catch (ClientException e) {
			throw e;
		}
	}

	public String getAccessKey() {
		//非主账号的ram的accessKeySecret
		return "LTAI5*****DDFt9ntw";
	}

	public AssumeRoleResponse getSTS() {

		String accessKeyId = getAccessKey();
		//非主账号的ram的accessKeySecret
		String accessKeySecret = "APNDvh*****mDoJa13X";
		String roleArn = "acs:ram::113*********4527:role/ossram";

		// 自定义角色会话名称
		String roleSessionName = "ramoss";

		//角色权限。 这个权限要小于等于你创建ram的权限
		String policy = "{\n" +
        "    \"Version\": \"1\",\n" +
        "    \"Statement\": [\n" +
        "        {\n" +
        "            \"Effect\": \"Allow\",\n" +
        "            \"Action\": \"oss:PutObject\",\n" +
	        		//你自己的oss地址
        "            \"Resource\": \"acs:oss:*:*:w********/*\"\n" +
        "        }\n" +
        "    ]\n" +
        "}";


		long durationSeconds = 3600L;
		try {
			return assumeRole(accessKeyId, accessKeySecret, roleArn, roleSessionName, policy, ProtocolType.HTTPS, durationSeconds);
		} catch (ClientException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
	}

	public String getPolicyBase64(AssumeRoleResponse response) {
		HashMap<String, Object> policyMap = new HashMap<String, Object>();

		int timeout = 1; // 设置过期时间为2小时

        // 获取当前时间,并加上过期时间
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR_OF_DAY, timeout);

        // 转换为ISO格式字符串
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
        String expiration = dateFormat.format(calendar.getTime());

		policyMap.put("expiration", response.getCredentials().getExpiration());
		
		/**
		 * 
		 	{
				"expiration":"2023-05-26T17:33:34Z",
				"conditions":[
					[
						"content-length-range",
						0,
						1048576
					]
				]
			}
		 */

		List<Object> conditionArray = new ArrayList<Object>();
		List<Object> contentLengthArray = new ArrayList<Object>();
		contentLengthArray.add("content-length-range");
		contentLengthArray.add(0);
		contentLengthArray.add(5242880); // 5M 
		conditionArray.add(contentLengthArray);
		policyMap.put("conditions", conditionArray);

		Gson gson = new Gson();
		String gsonString = gson.toJson(policyMap);

		String encodedStr = Base64.getEncoder().encodeToString(gsonString.getBytes());
		return encodedStr;
	}

	public String getSignature(String policyBase64, AssumeRoleResponse response) throws Exception {
        Mac hmac = Mac.getInstance("HmacSHA1");
		String accessKeySecret = response.getCredentials().getAccessKeySecret();
        SecretKeySpec keySpec = new SecretKeySpec(accessKeySecret.getBytes(StandardCharsets.UTF_8), "HmacSHA1");
        hmac.init(keySpec);
        byte[] hmacBytes = hmac.doFinal(policyBase64.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(hmacBytes);
    }

	public String getHost() {
		//你自己的oss地址
		return "https://w*******.oss-cn-beijing.aliyuncs.com";
	}



	public String getUserPath() {
		//path是唯一 自己定义
		String path="";
		return "user/" +path
	}
}
AliyunController
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;

import demo.example.demo.service.AliyunSTSService;
import demo.example.demo.utils.ApiResponse;
import demo.example.demo.vo.STSVo;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

//
@RestController
@RequestMapping("/api/aliyun")
@AllArgsConstructor
public class AliyunController {

    private AliyunSTSService aliyunSTS;

    @ApiOperation(value = "sts")
    @GetMapping("/sts")
    public ApiResponse<STSVo> getSTSInfo(){
        AssumeRoleResponse assumeRoleResponse = aliyunSTS.getSTS();
        String policy = aliyunSTS.getPolicyBase64(assumeRoleResponse);
        String signature;
        try {
            signature = aliyunSTS.getSignature(policy, assumeRoleResponse);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return ApiResponse.fail("签名获取失败", null);
        }

        String path = "wang";

        STSVo vo = STSVo.builder()
                        .host(aliyunSTS.getHost())
                        .ossAccessKeyId(assumeRoleResponse.getCredentials().getAccessKeyId())
                        .signature(signature)
                        .accessKeySecret(assumeRoleResponse.getCredentials().getAccessKeySecret())
                        .policy(policy)
                        .userPath(path)
                        .securityToken(assumeRoleResponse.getCredentials().getSecurityToken())
                        .build();

        return ApiResponse.success(vo, "签名获取成功");
    }
}

Vue前端

vue这里我使用的是vant组件,elementUI组件上传方式一样,只不过两种组件的上传组件的函数调用返回值不一样 可以去官网了解
vant官网:van2官网

阿里云的oss模块

npm i ali-oss

uploader组件

			  <van-uploader
              :show-file-list="false"
              :after-read="fnUploadRequest"
            >
              <van-image
                style="border: thin solid #000000;"
                v-if="this.user.photo"
                :src="this.user.photo"
                width="4rem"
                height="4rem"
              />

            
            </van-uploader>

JS部分

 getSts() {
      this.request.get("/api/aliyun/sts").then((res) => {
        console.log(res);
        this.sts = res.data;
      });
    },
fnUploadRequest(file) {
      // console.log(file);
      if (
        this.sts.ossAccessKeyId != null &&
        this.sts.ossAccessKeyId != undefined
      ) {
        const client = new OSS({
          region: "oss-cn-beijing",
          accessKeyId: this.sts.ossAccessKeyId,
          accessKeySecret: this.sts.accessKeySecret,
          stsToken: this.sts.securityToken,
          bucket: "wyh*****",
          secure: true,
  
        });

        file.status = "uploading";
        file.message = "上传中...";
        var len = len || 16;
        var $chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
        var maxPos = $chars.length;
        var pwd = "";
        for (let i = 0; i < len; i++) {
          pwd += $chars.charAt(Math.floor(Math.random() * maxPos)); // 生成16位随机字符
        }
        let name = file.file.name;
        var pos = name.indexOf(".");
        let type = name.substr(pos);
        //accompany是我oss的文件路径
        var fileName = "accompany/" + `${Date.parse(new Date())}` + pwd + type; // 文件名称(时间戳+随机字符+后缀)
        client
          .multipartUpload(fileName, file.file)
          .then((res) => {
            // console.log("res", res.res.requestUrls[0]);
            let imageUrlObj = {};
            imageUrlObj.fileName = res.res.requestUrls[0];
            imageUrlObj.fileUrl = res.res.requestUrls[0];
            imageUrlObj.fileType = 1;
            imageUrlObj.type = 1;
            console.log(imageUrlObj);
            this.user.photo = imageUrlObj.fileUrl.split("?uploadId")[0];
            //你的业务
            file.status = "";
            file.message = "";
          })
          .catch((err) => {
            console.log(err);
          });
         console.log(file);
      } else {
        Toast.fail("上传失败");
        return;
      }
    },
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值