golang 使用aws IAM 访问s3服务,上传图片,并公共访问权限

aws有两种账户类型MFA 和IAM
MFA 根用户
IAM 由根用户衍生的权限受控用户
在这里插入图片描述
IAM链接:https://us-east-1.console.aws.amazon.com/iamv2/home#/home
在这里插入图片描述

这里有几个坑 :
1: 不明白aws的endpoint 具体指什么,没有看到官文有哪里告知了这个 endpoint是啥,(试了也不是接入点)这个url是自己试出来的。
2: 首先要去开一个IAM用户,然后要配置accessKey和secretKey ,和 权限策略才可以使用。安全凭证(accessKey和secretKey )在IAM里设置步骤:
https://us-east-1.console.aws.amazon.com/iamv2/home?region=us-east-1#/users
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
这里有个坑就是 就算你设置好IAM用户,也给IAM用户生成了访问密钥,但是在代码里执行的时候还是AccessDenied. 原因是要给IAM用户配置访问权限(IAM用户策略中缺乏在s3上执行操作的权限),参考:https://aws.amazon.com/cn/premiumsupport/knowledge-center/athena-access-denied-status-code-403/
https://repost.aws/zh-Hans/knowledge-center/s3-troubleshoot-403

在策略中创建策略然后附加到IAM用户

在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
或者在用户的权限那里添加内联策略。
在这里插入图片描述
直接使用可视化编辑器去控制策略。json格式的因为不熟就不要自己写了。在这里还可以限制IAM的访问ip,可以将它限制为公司服务器的公网ip和自己本地调试时候的公网ip。
这个策略可以以后在 用户-权限-权限策略-策略名称- (点进去) 那里更新。
这是使用IAM用户,其实也可以直接使用MFA根用户创建访问密钥。根用户的密钥可以直接使用,拥有所有权限,不需要配置权限策略。
添加MFA
在这里插入图片描述
创建访问密钥
在这里插入图片描述
可以看到并不建议这么做,

在这里插入图片描述
所以我们使用IAM就好。

下面上代码,代码如下:

package service

import (
   "fmt"
   "github.com/aws/aws-sdk-go/aws"
   "github.com/aws/aws-sdk-go/aws/credentials"
   "github.com/aws/aws-sdk-go/aws/session"
   "github.com/aws/aws-sdk-go/service/s3"
   "github.com/aws/aws-sdk-go/service/s3/s3manager"
   "mime/multipart"
   "os"
   "stargate_backend/utils"
   "strconv"
)
/*
这里是前端传到后端文件,使用的是*multipart.FileHeader格式。不是直接在本地用os.open()打开。
*/
var (
   // IAM账户  需要在IAM添加合适的访问策略 才有s3服务的访问权限
   accessKey = "xxxx"                     
   secretKey = "xxxxxxx" 
   //根用户 MFA 非最佳实践 但具有根权限 无需配置权限 可以直接使用
   //accessKey = "xxxx"                     
   //secretKey = "xx/xxx" 
   region = "ap-northeast-1"
   endpoint = "https://s3.ap-northeast-1.amazonaws.com/"
   svc *s3.S3
)

func AWSInit() error {
    
    
   //只要不修改session,session就可以安全的并发使用。
   sess, err := session.NewSession(&aws.Config{
    
    
   	Credentials: credentials.NewStaticCredentials(accessKey, secretKey, ""),
   	Endpoint:    aws.String(endpoint),
   	Region:      aws.String(region),
   	//minio:true,oss:false
   	S3ForcePathStyle: aws.Bool(false),
   	//SDK 支持使用客户端 TLS 证书配置的环境和会话选项,这些证书作为客户端 TLS 握手的一部分发送以进行客户端身份验证。
   	//如果使用,则需要 Cert 和 Key 值。如果缺少一个,或者无法加载文件的内容,则会返回一个错误。
   	//ClientTLSCert:              nil,
   	//ClientTLSKey:               nil,
   })
   if err != nil {
    
    
   	panic(err)

   }

   svc = s3.New(sess)
   return err
}

//S3 上传管理器确定文件是否可以拆分为更小的部分并并行上传。您可以自定义并行上传的数量和上传部分的大小。
func AWSUploadWithClient(file *multipart.FileHeader, svc *s3.S3, dir string) (string, error) {
    
    
   uploader := s3manager.NewUploaderWithClient(svc, func(u *s3manager.Uploader) {
    
    
   	//定义将在内存中缓冲25个MiB的策略
   	//u.BufferProvider = s3manager.NewBufferedReadSeekerWriteToPool(25 * 1024 * 1024)
   	//指定要上传的每个部分的缓冲区大小(以字节为单位)。每个部分的最小大小为 5 MB。 DefaultUploadPartSize
   	u.PartSize = 64 * 1024 * 1024 // 每个部分 64MB
   	//	指定要并行上传的part数量。 默认为5
   	u.Concurrency = s3manager.DefaultUploadConcurrency
   })
   open, err := file.Open() //  可以通过一个*multipart.FileHeader 的open() 方法的获取一个multipart.File文件 它实现了io.Reader接口
   if err != nil {
    
    
   	return "", err
   }
   id, _ := utils.GenID()
   var xxx = "你的桶名字"
   uploadOutput, err := uploader.Upload(&s3manager.UploadInput{
    
    
   	Body:   open,                                     // io.Reader类型
   	Bucket: aws.String(xxx),                      // 指定要上传的bucket
   	Key:    aws.String(dir + "/" + strconv.Itoa(id)), // 如果bucket下边有文件夹,那么通过在key前加上指定路径,来达到上传到指定文件夹的效果。
   	ACL:    aws.String("public-read"),                // 指定ACL权限。一般上传图片类的都是期望可以在前端通过url获取资源的,为public-read。具体可以参考 https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/userguide/acl-overview.html#CannedACL
   })
   if err != nil {
    
    
   	if multierr, ok := err.(s3manager.MultiUploadFailure); ok {
    
    
   		// Process error and its associated uploadID
   		fmt.Println("Error:", multierr.Code(), multierr.Message(), multierr.UploadID())
   	} else {
    
    
   		// Process error generically
   		fmt.Println("Error:", err.Error())
   	}

   	return "", err
   }
   
   url := "https://xxx.s3.ap-northeast-1.amazonaws.com/" + dir + "/" + strconv.Itoa(id)
   fmt.Printf("UploadID:%s\n", uploadOutput.UploadID)
   fmt.Printf("ETag:%s\n", *uploadOutput.ETag)
   fmt.Printf("Location:%s\n", uploadOutput.Location)
   return url, err
}
//https://docs.aws.amazon.com/zh_cn/sdk-for-go/v1/developer-guide/sdk-utilities.html
//传输管理器 上传和下载管理器可以分解大型对象,以便可以将它们分成多个部分并行传输。这使得恢复中断的传输变得容易。
//S3 下载管理器确定文件是否可以拆分为更小的部分并并行下载。您可以自定义并行下载的数量和下载部分的大小。
func DownloadWithClient(svc *s3.S3, bucket, key string) {
    
    
   download := s3manager.NewDownloaderWithClient(svc, func(d *s3manager.Downloader) {
    
    
   	d.PartSize = 64 * 1024 * 1024 // 64MB per part
   	//d.BufferProvider = s3manager.NewPooledBufferedWriterReadFromProvider(25 * 1024 * 1024)
   })

   f, err := os.Create("d_" + key)
   if err != nil {
    
    
   	panic(err)
   }
   defer f.Close()
   n, err := download.Download(f, &s3.GetObjectInput{
    
    
   	Bucket: aws.String(bucket),
   	Key:    aws.String(key),
   })
   if err != nil {
    
    
   	panic(err)
   }
   fmt.Printf("Download.n:%d\n", n)
}

猜你喜欢

转载自blog.csdn.net/qq_37106501/article/details/128860064
IAM