范文健康探索娱乐情感热点
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

Go实现AWS4请求认证

  什么是 Amazon S3?它是 AWS 提供的一种对象存储服务,提供行业领先的可扩展性、数据可用性、安全性和性能。Amazon S3 可达到 99.999999999%(11 个 9)的持久性。
  Amazon S3 里用到了  AWS Signature Version 4  (下面简称 AWS4  )做认证请求,这篇文章将会讲解如何使用 Go 实现 AWS4 请求认证。
  转自:https://juejin.cn/post/6950300506946273294
  整理:地鼠文档www.topgoer.cn
  AWS4 是一种用于对所有 AWS 区域服务的入站 API 请求进行身份验证的协议。 AWS4
  AWS4 对请求进行签名有以下优势(但这也取决于你如何使用): 验证请求者的身份  - 经过身份验证的请求需要使用  AccessKeyID   和 SecretAccessKey   创建签名。保护传输中的数据  - 为了防止在传输过程中对请求进行篡改,可以使用一些请求元素(比如 请求路径  、请求头  等)来计算请求签名。Amazon S3 在收到请求后,使用相同的请求元素来计算签名。如果 Amazon S3 接收到的任何请求组件与用于计算签名的组件不匹配,Amazon S3 将拒绝该请求。防止重用请求的签名部分  - 请求的签名部分在请求中的时间戳的一段时间内有效。 授权方式HTTP 身份验证头,例如 Authorization 请求头: Authorization: AWS4-HMAC-SHA256  Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request,  SignedHeaders=host;range;x-amz-date, Signature=fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024URL 查询字符串参数,例如预签名 URL: https://s3.amazonaws.com/examplebucket/test.txt ?X-Amz-Algorithm=AWS4-HMAC-SHA256 &X-Amz-Credential=/20130721/us-east-1/s3/aws4_request &X-Amz-Date=20130721T201207Z &X-Amz-Expires=86400 &X-Amz-SignedHeaders=host &X-Amz-Signature=Go 实现 HTTP 身份验证头HTTP 身份验证头组成部分AWS4-HMAC-SHA256  - 该字符串指定 AWS4 和签名算法(HMAC-SHA256)。 Credential  - 指定 AccessKeyID、计算签名的日期、区域和服务。它的格式是 ////aws4_request  ,date   的格式是 YYYYMMDD  。SignedHeaders  - 指定用于计算签名的请求头列表,以分号分隔。仅包含请求头的名称,且必须是小写,例如: host;range;x-amz-date  。Signature  - 表示为 64 个小写十六进制字符的 256 位签名,例如: fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024  。上传图片至掘金
  根据对 AWS4 请求认证的学习,并参考 simples3 的代码实现了 上传图片至掘金(字节跳动的存储服务,其服务名称是 imagex  )的功能,下面是部分的代码实现(主要省略了Client   部分的实现,完整代码有待后续完善后进行开源):package juejin  import (     "bytes"     "crypto/hmac"     "crypto/sha256"     "encoding/hex"     "encoding/json"     "fmt"     "hash/crc32"     "io"     "io/ioutil"     "net/http"     "net/url"     "os"     "path/filepath"     "regexp"     "sort"     "strings"     "time"      "github.com/tidwall/gjson" )  const (     amzDateISO8601TimeFormat = "20060102T150405Z"     shortTimeFormat          = "20060102"     algorithm                = "AWS4-HMAC-SHA256"     serviceName              = "imagex"     serviceID                = "k3u1fbpfcp"     version                  = "2018-08-01"     uploadURLFormat          = "https://%s/%s"      RegionCNNorth = "cn-north-1"      actionApplyImageUpload  = "ApplyImageUpload"     actionCommitImageUpload = "CommitImageUpload"      polynomialCRC32 = 0xEDB88320 )  var (     newLine = []byte{" "}      // if object matches reserved string, no need to encode them     reservedObjectNames = regexp.MustCompile("^[a-zA-Z0-9-_.~/]+#34;) )  type ImageX struct {     AccessKey string     SecretKey string     Region    string     Client    *http.Client      Token   string     Version string     BaseURL string }  type UploadToken struct {     AccessKeyID     string `json:"AccessKeyID"`     SecretAccessKey string `json:"SecretAccessKey"`     SessionToken    string `json:"SessionToken"` }  func (c *Client) UploadImage(region, imgPath string) (string, error) {     uploadToken, err := c.GetUploadToken()     if err != nil {         return "", err     }      ix := &ImageX{         AccessKey: uploadToken.AccessKeyID,         SecretKey: uploadToken.SecretAccessKey,         Token:     uploadToken.SessionToken,         Region:    region,     }      applyRes, err := ix.ApplyImageUpload()     if err != nil {         return "", err     }      storeInfo := gjson.Get(applyRes, "Result.UploadAddress.StoreInfos.0")     storeURI := storeInfo.Get("StoreUri").String()     storeAuth := storeInfo.Get("Auth").String()     uploadHost := gjson.Get(applyRes, "Result.UploadAddress.UploadHosts.0").String()     uploadURL := fmt.Sprintf(uploadURLFormat, uploadHost, storeURI)     if err := ix.Upload(uploadURL, imgPath, storeAuth); err != nil {         return "", err     }      sessionKey := gjson.Get(applyRes, "Result.UploadAddress.SessionKey").String()     if _, err = ix.CommitImageUpload(sessionKey); err != nil {         return "", err     }      return c.GetImageURL(storeURI) }  func (c *Client) GetImageURL(uri string) (string, error) {     endpoint := "/imagex/get_img_url"     params := &url.Values{         "uri": []string{uri},     }     raw, err := c.Get(APIBaseURL, endpoint, params)     if err != nil {         return "", err     }     rawurl := gjson.Get(raw, "data.main_url").String()     return rawurl, nil }  func (c *Client) GetUploadToken() (*UploadToken, error) {     endpoint := "/imagex/gen_token"     params := &url.Values{         "client": []string{"web"},     }     raw, err := c.Get(APIBaseURL, endpoint, params)     if err != nil {         return nil, err     }     var token *UploadToken     err = json.Unmarshal([]byte(gjson.Get(raw, "data.token").String()), &token)     return token, err }  func (ix *ImageX) ApplyImageUpload() (string, error) {     rawurl := fmt.Sprintf("https://imagex.bytedanceapi.com/?Action=%s&Version=%s&ServiceId=%s",         actionApplyImageUpload, version, serviceID)     req, err := http.NewRequest(http.MethodGet, rawurl, nil)     if err != nil {         return "", err     }      if err := ix.signRequest(req); err != nil {         return "", err     }      res, err := ix.getClient().Do(req)     if err != nil {         return "", err     }     defer res.Body.Close()     b, err := ioutil.ReadAll(res.Body)     if err != nil {         return "", err     }     raw := string(b)     if res.StatusCode != 200 || gjson.Get(raw, "ResponseMetadata.Error").Exists() {         return "", fmt.Errorf("raw: %s, response: %+v", raw, res)     }     return raw, nil }  func (ix *ImageX) CommitImageUpload(sessionKey string) (string, error) {     rawurl := fmt.Sprintf("https://imagex.bytedanceapi.com/?Action=%s&Version=%s&SessionKey=%s&ServiceId=%s",         actionCommitImageUpload, version, sessionKey, serviceID)     req, err := http.NewRequest(http.MethodPost, rawurl, nil)     if err != nil {         return "", err     }      if err := ix.signRequest(req); err != nil {         return "", err     }      res, err := ix.getClient().Do(req)     if err != nil {         return "", err     }     defer res.Body.Close()     b, err := ioutil.ReadAll(res.Body)     if err != nil {         return "", err     }     raw := string(b)     if res.StatusCode != 200 || gjson.Get(raw, "ResponseMetadata.Error").Exists() {         return "", fmt.Errorf("raw: %s, response: %+v", raw, res)     }     return raw, nil }  func (ix *ImageX) getClient() *http.Client {     if ix.Client == nil {         return http.DefaultClient     }     return ix.Client }  func (ix *ImageX) signKeys(t time.Time) []byte {     h := makeHMac([]byte("AWS4"+ix.SecretKey), []byte(t.Format(shortTimeFormat)))     h = makeHMac(h, []byte(ix.Region))     h = makeHMac(h, []byte(serviceName))     h = makeHMac(h, []byte("aws4_request"))     return h }  func (ix *ImageX) writeRequest(w io.Writer, r *http.Request) error {     r.Header.Set("host", r.Host)      w.Write([]byte(r.Method))     w.Write(newLine)     writeURI(w, r)     w.Write(newLine)     writeQuery(w, r)     w.Write(newLine)     writeHeader(w, r)     w.Write(newLine)     w.Write(newLine)     writeHeaderList(w, r)     w.Write(newLine)     return writeBody(w, r) }  func (ix *ImageX) writeStringToSign(w io.Writer, t time.Time, r *http.Request) error {     w.Write([]byte(algorithm))     w.Write(newLine)     w.Write([]byte(t.Format(amzDateISO8601TimeFormat)))     w.Write(newLine)      w.Write([]byte(ix.creds(t)))     w.Write(newLine)      h := sha256.New()     if err := ix.writeRequest(h, r); err != nil {         return err     }     fmt.Fprintf(w, "%x", h.Sum(nil))     return nil }  func (ix *ImageX) creds(t time.Time) string {     return t.Format(shortTimeFormat) + "/" + ix.Region + "/" + serviceName + "/aws4_request" }  func (ix *ImageX) signRequest(req *http.Request) error {     t := time.Now().UTC()     req.Header.Set("x-amz-date", t.Format(amzDateISO8601TimeFormat))      req.Header.Set("x-amz-security-token", ix.Token)      k := ix.signKeys(t)     h := hmac.New(sha256.New, k)      if err := ix.writeStringToSign(h, t, req); err != nil {         return err     }      auth := bytes.NewBufferString(algorithm)     auth.Write([]byte(" Credential=" + ix.AccessKey + "/" + ix.creds(t)))     auth.Write([]byte{",", " "})     auth.Write([]byte("SignedHeaders="))     writeHeaderList(auth, req)     auth.Write([]byte{",", " "})     auth.Write([]byte("Signature=" + fmt.Sprintf("%x", h.Sum(nil))))      req.Header.Set("authorization", auth.String())     return nil }  func writeURI(w io.Writer, r *http.Request) {     path := r.URL.RequestURI()     if r.URL.RawQuery != "" {         path = path[:len(path)-len(r.URL.RawQuery)-1]     }     slash := strings.HasSuffix(path, "/")     path = filepath.Clean(path)     if path != "/" && slash {         path += "/"     }     w.Write([]byte(path)) } func writeQuery(w io.Writer, r *http.Request) {     var a []string     for k, vs := range r.URL.Query() {         k = url.QueryEscape(k)         for _, v := range vs {             if v == "" {                 a = append(a, k)             } else {                 v = url.QueryEscape(v)                 a = append(a, k+"="+v)             }         }     }     sort.Strings(a)     for i, s := range a {         if i > 0 {             w.Write([]byte{"&"})         }         w.Write([]byte(s))     } }  func writeHeader(w io.Writer, r *http.Request) {     i, a := 0, make([]string, len(r.Header))     for k, v := range r.Header {         sort.Strings(v)         a[i] = strings.ToLower(k) + ":" + strings.Join(v, ",")         i++     }     sort.Strings(a)     for i, s := range a {         if i > 0 {             w.Write(newLine)         }         io.WriteString(w, s)     } }  func writeHeaderList(w io.Writer, r *http.Request) {     i, a := 0, make([]string, len(r.Header))     for k := range r.Header {         a[i] = strings.ToLower(k)         i++     }     sort.Strings(a)     for i, s := range a {         if i > 0 {             w.Write([]byte{";"})         }         w.Write([]byte(s))     } }  func writeBody(w io.Writer, r *http.Request) error {     var (         b   []byte         err error     )     // If the payload is empty, use the empty string as the input to the SHA256 function     // http://docs.amazonwebservices.com/general/latest/gr/sigv4-create-canonical-request.html     if r.Body == nil {         b = []byte("")     } else {         b, err = ioutil.ReadAll(r.Body)         if err != nil {             return err         }         r.Body = ioutil.NopCloser(bytes.NewBuffer(b))     }      h := sha256.New()     h.Write(b)     fmt.Fprintf(w, "%x", h.Sum(nil))     return nil }  func makeHMac(key []byte, data []byte) []byte {     hash := hmac.New(sha256.New, key)     hash.Write(data)     return hash.Sum(nil) }  func (ix *ImageX) Upload(rawurl, fp, auth string) error {     crc32, err := hashFileCRC32(fp)     if err != nil {         return err     }     file, err := os.Open(fp)     if err != nil {         return err     }     defer file.Close()      req, err := http.NewRequest(http.MethodPost, rawurl, file)     if err != nil {         return err     }     req.Header.Add("authorization", auth)     req.Header.Add("Content-Type", "application/octet-stream")     req.Header.Add("content-crc32", crc32)     res, err := http.DefaultClient.Do(req)     if err != nil {         return err     }     defer res.Body.Close()     b, err := ioutil.ReadAll(res.Body)     if err != nil {         return err     }     raw := string(b)     if gjson.Get(raw, "success").Int() != 0 {         return fmt.Errorf("raw: %s, response: %+v", raw, res)     }     return nil }  // hashFileCRC32 generate CRC32 hash of a file // Refer https://mrwaggel.be/post/generate-crc32-hash-of-a-file-in-golang-turorial/ func hashFileCRC32(filePath string) (string, error) {     file, err := os.Open(filePath)     if err != nil {         return "", err     }     defer file.Close()     tablePolynomial := crc32.MakeTable(polynomialCRC32)     hash := crc32.New(tablePolynomial)     if _, err := io.Copy(hash, file); err != nil {         return "", err     }     return hex.EncodeToString(hash.Sum(nil)), nil }

中国股市只有5大高端制造企业,能与宁德媲美高端制造业是指在后工业化时代具有高技术含量和高附加值的制造产业,是工业化发展的高级阶段,其显著特征是高技术高附加值低污染低排放,具有较强的竞争优势。其次,高端制造承载了中国未来工业走下神坛的马老师走下神坛的马老师据媒体报道,马云先生彻底离开了阿里,风清扬从此又回到了书里。话说杰克马,以他阿里巴巴成功以前的成就,他就是凡人一个,颜值和才华,是否与他都没特别关系。我们不必说他参我们至今仍未找到一位互联网退休员工作者蓝字原创首发蓝字计划90万免息贷款,你知道是什么概念吗?隔着电话,程惟噼里啪啦开始算帐。90万,按照目前银行5的首套房贷款利率来算,等额本息六年,需要偿还的利息总额大约为14。OPPOFindN元宇宙奇旅NFT限定礼盒,将于12月23日正式开售OPPO推出FindN元宇宙奇旅NFT限定礼盒,将于12月23日上午10点在京东限量抢购。OPPOFindN元宇宙奇旅NFT限定礼盒是OPPO携手肉比特Roubit数字艺术工作室,这些曾经非常流行的手机设计,如今销声匿迹了,你都用过吗?最近的一波新机,还是让机哥有些眼花缭乱。虽然一直都说智能手机同质化严重,什么没有创新之类的。但是实际上每年还是有不少新东西,但只有少数能真正戳中用户的痛点。那些经过市场验证,留下来iOS15。3beta出来了,有想法要降到15。1。1的别犹豫了最近的几个版本评价都不算太好,但是相对来说我认为iOS15。1。1是最值得最近一段时间保留的系统。如果不是新功能必须要用,那就抓紧时间降级吧。我用的是iPhone13,iOS15。中国鸡老是跑去美国鸡窝下蛋据相关统计显示我们国家芯片的人才缺口约在60万左右。人才外流高校人才培养能力或成主因。据半导体大佬尹志尧icon回忆,1984年,自己到英特尔,原本以为这里搞研发的都是美国人,结果互联网巨头为何频频发力?是陷阱还是蛋糕?大家好,我是明灯,互联网创业导师,你的创业路上的引路人。众所周知,明灯一般很少讲解短期项目,因为在我看来,短期项目并不是一个可以长久赚钱之计,而我今天为什么介绍呢?支付宝,作为我们今天,全网都在骂这个网站两年前,翟天临博士喊出了一句知网是什么东西?简单的一句话,就让翟天临被全网嘲讽,同时还丢掉了博士学位。知网号称中国知识基础设施工程,是在国家大力扶持下建成的,世界上全文信息量规模最大众电气化进程再提速MEB助力ID。家族快速上量来源中国经济网郭涛目前,大众电动化转型的先锋车型ID。家族在华销量,正呈现快速攀升趋势。自3月首款车型上市以来,短短几个月的时间,ID。家族即在中国市场推出五款车型,快速形成从A级什么是Kubernetes?Kubernetes是怎样工作的?什么是Kubernetes?Kubernetes是一个可移植可扩展的开源平台,用于管理容器化工作负载和服务,有助于声明式配置和自动化,它拥有庞大且快速发展的生态系统,Kuberne
多家跨国车企拟建中国数据中心,汽车数据监管起步近日,国家网信办就汽车数据安全管理若干规定(征求意见稿)(以下简称规定)公开征集意见,意在将这些智能网联汽车数据纳入规范管理。尽管仍在征求意见阶段,市场已有所反馈。作为智能汽车领头红米Note10pro对比note9pro,可谓做到了全面提升同样是6128g内存note10pro,就比note9pro贵了100块钱,但是配置上面可谓做到了全面提升。这些配置远远100元买不到的。红米Note10pro可以说在这个价位上,线下店铺全面覆盖,小米之家来到每个米粉身边小米之家是小米公司直营的客户服务中心,在小米之家可以获得关于小米官方产品最全面的产品信息,并且能够在购买之前就产品进行体验,同时小米之家也是米粉之间进行交流的场所。小米之家是从205月27日,网红二驴夫妇卖假货被调查5月27日,网红二驴夫妇,在直播间带货山寨手机被相关部门介入调查。这个在快手拥有几千万粉丝的人,卖过多种不同品牌的山寨手机,营销额高达4。7亿元。而消费者们根本不知道他们卖的是山寨在北京有惊喜!京东618北京消费季专属消费券5月31日开枪北京消费季6月惠聚海量消费补贴,新一轮活动蓄势待发。一年一度的京东618狂欢节也强势来袭,品质好物纷纷入场,优惠活动不断加码。作为继五一之后2021北京消费季新一轮普惠发券活动,在亚马逊买下米高梅之后,下一个媒体巨兽并购案是谁?上周,流媒体界敲定一项重磅收购案。亚马逊同意以84。5亿美元收购米高梅。该交易是亚马逊公司历史上第二大收购,仅次于亚马逊在2017年以137亿美元对全食超市(WholeFoodsM云茶网正式上线致力推动云茶产业升级来源云南日报近日,天则控股旗下云茶产业互联网第一平台云茶网完成公测,正式发布上线。云茶网将面向用户正式开放注册登录入口,并提供在线交易撮合交易电子签章等多个功能及服务,云茶产业互联什么情况?荣耀还没有拿谷歌全家桶授权一个事实华为去年受到不公平待遇之时率先出现问题的就是海外市场,这是由于华为无法获得谷歌全家桶的授权,而海外用户对于谷歌全家桶的依赖程度远远超出我们的想象。所以这就是华为为什么要做自跨境电商迅猛崛起来源中国经济周刊经济网中国经济周刊记者李永华忽然之间,跨境电商成了市场关注的大风口。据海关初步统计,2020年我国跨境电商进出口1。69万亿元,增长了31。1,其中出口1。12万亿Mate40系列或成末代机皇,华为P50再延期今年上半年,华为已经召开了三场发布会,发布了全屋智能解决方案和各类外设硬件,还更新了mateX2折叠屏手机,但却不见本该于上半年发布的p系列的身影。这次华为将在6月2日召开以鸿蒙OiPhone13系列配置曝光,影像有看点,小刘海实锤即使前一段时间苹果以紫色版的iPhone12来保持iPhone12的热度,但由于iPhone12整体性能带给果粉的强烈落差感,大家似乎更为期待iPhone13的到来。按照以往的发布