go语言调用s3接口通过rgw节点创建ceph用户

这段 Go 代码是用于创建 Ceph 用户并获取其 S3 访问密钥的示例。已经过实际应用可以直接拿来使用

导入的包

Go 复制代码
import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/json"
	"net/http"
	"net/url"
	"fmt"
	"io"
	"time"
	"errors"
	"encoding/base64"
)

这些包提供了加密、网络请求、时间处理、输入输出等功能,是实现本功能所必需的。

辅助函数:makeHMac

Go 复制代码
func makeHMac(key []byte, data []byte) []byte {
	hash := hmac.New(sha1.New, key)
	hash.Write(data)
	return hash.Sum(nil)
}

这个函数用于生成 HMAC(Hash-based Message Authentication Code),这是一种用于消息认证的安全码,可以防止信息被篡改。

数据结构定义

Go 复制代码
type Response struct {
	Keys []Credentials `json:"keys"`
}

type Credentials struct {
	AccessKey string `json:"access_key"`
	SecretKey string `json:"secret_key"`
	User      string `json:"user"`
}

Response 和 Credentials 结构体用于解析从 Ceph 返回的 JSON 数据。这些数据包含了用户的访问密钥和密钥。

主函数:CreateCephUser

Go 复制代码
func CreateCephUser(uid, display, email, accessKey, secretKey string) (s3key, secret string, err error) {
	...
}

这个函数接受用户 ID、显示名、电子邮件地址以及可选的访问密钥和密钥,返回新创建的 S3 访问密钥和密钥。

构建请求 URL

Go 复制代码
baseURL := "http://192.168.1.224:80/admin/user?format=json"
u, err := url.Parse(baseURL)
...
queryParams := url.Values{}
...
u.RawQuery = queryParams.Encode()

这部分代码构建了一个 HTTP 请求的 URL,包括必要的查询参数。

创建和发送 HTTP 请求

Go 复制代码
req, err := http.NewRequest("PUT", u.String(), nil)
...
signature := makeHMac([]byte(cephConn.Secret), []byte(strToSign))
...
resp, err := client.Do(req)

这里创建了一个 HTTP PUT 请求,用于向 Ceph 发送创建用户的命令。请求中包含了通过 HMAC 签名的授权头,确保请求的安全性。

处理响应

Go 复制代码
bodyBytes, err := io.ReadAll(resp.Body)
...
var response Response
if err := json.Unmarshal(bodyBytes, &response); err != nil {
	...
}

完整代码如下:

Go 复制代码
package ceph

import (
	"crypto/hmac"
	"crypto/sha1"
	"encoding/json"
	"net/http"
	"net/url"
	"fmt"
	"io"
	"time"
	"errors"
	"encoding/base64"
)

func makeHMac(key []byte, data []byte) []byte {
	hash := hmac.New(sha1.New, key)
	hash.Write(data)
	return hash.Sum(nil)
}

type Response struct {
	Keys []Credentials `json:"keys"`
}

type Credentials struct {
	AccessKey string `json:"access_key"`
	SecretKey string `json:"secret_key"`
	User      string `json:"user"`
}


func CreateCephUser(uid, display, email, accessKey, secretKey string) (s3key, secret string, err error){
	// session = GetCephAdminConn()
	client := &http.Client{}

	//url
	baseURL := "http://192.168.1.224:80/admin/user?format=json"

	// 创建 URL 对象
	u, err := url.Parse(baseURL)
	if err != nil {
		//.GetLogger().Errorf("Error parsing base URL: %v", err)
		return "", "", err
	}

	// 创建 URL 查询参数
	queryParams := url.Values{}
	queryParams.Add("uid", uid)
	queryParams.Add("display-name", display)
	queryParams.Add("email", email)
	queryParams.Add("user-caps", "usage=read;users=read;buckets=read,write;metadata=read")
	if accessKey != "" && secretKey != "" {
		queryParams.Add("access-key", accessKey)
		queryParams.Add("secret-key", secretKey)
	}

	// 将查询参数添加到 URL
	u.RawQuery = queryParams.Encode()

	// 创建请求
	req, err := http.NewRequest("PUT", u.String(), nil)
	if err != nil {
		//.GetLogger().Errorf("Error creating request: %v", err)
		return "", "", err
	}

	// 生成签名
	utcTime := time.Now().UTC()
	timestamp := utcTime.Format("Mon, 2 Jan 2006 15:04:05") + " +0000"
	strToSign := "PUT\n\n\n" + timestamp + "\n/admin/user"
	signature := makeHMac([]byte(cephConn.Secret), []byte(strToSign))

	req.Header.Add("Date", timestamp)
	req.Header.Add("Authorization", "AWS "+cephConn.S3key+":"+base64.StdEncoding.EncodeToString(signature))

	resp, err := client.Do(req)
	if err != nil {
		//your_logger_package.GetLogger().Errorf("Error sending request: %v", err)
		return "", "", err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		//bodyBytes, _ := io.ReadAll(resp.Body)
		//your_logger_package.GetLogger().Warnf("Request not ok with status: %d, body: %s", resp.StatusCode, string(bodyBytes))
		return "", "", fmt.Errorf("request failed with status: %d", resp.StatusCode)
	}

	// 读取响应体内容
	bodyBytes, err := io.ReadAll(resp.Body)
	if err != nil {
		//your_logger_package.GetLogger().Errorf("Error reading response body: %v", err)
		return "", "", err
	}

	// 解析响应内容
	var response Response
	if err := json.Unmarshal(bodyBytes, &response); err != nil {
		//your_logger_package.GetLogger().Errorf("Error parsing response: %v", err)
		return "", "", err
	}

	if len(response.Keys) > 0 {
		s3key = response.Keys[0].AccessKey
		secret = response.Keys[0].SecretKey
	} else {
		return "", "", errors.New("no keys found in the response")
	}

	return s3key, secret, nil
}

由此我们可以衍生出对ceph的上传,下载,删除等功能函数,如下:

Go 复制代码
func (session *StorageSession) UploadObject(objectKey string, content []byte) error
func (session *StorageSession) DeleteObject(key string) error
func (session *StorageSession) DownloadObject(objectKey string)

完整的函数实现放在网盘了,自取:https://pan.quark.cn/s/d0a005cfb3ae

相关推荐
chxii1 小时前
18.2.go语言redis中使用lua脚本
redis·go·lua
用户0142260029842 小时前
Go语言 Map 详解
go
孔令飞2 小时前
Go 1.24 中的弱指针包 weak 使用介绍
人工智能·云原生·go
我的golang之路果然有问题16 小时前
速成GO访问sql,个人笔记
经验分享·笔记·后端·sql·golang·go·database
M1A119 小时前
云原生第一步:Windows Go环境极速配置
后端·go
纪元A梦21 小时前
华为OD机试真题——推荐多样性(2025A卷:200分)Java/python/JavaScript/C++/C语言/GO六种最佳实现
java·javascript·c++·python·华为od·go·华为od机试题
K8sCat1 天前
Golang与Kafka的五大核心设计模式
后端·kafka·go
孔令飞1 天前
Go:终于有了处理未定义字段的实用方案
人工智能·云原生·go
唐僧洗头爱飘柔95271 天前
(Go Gin)上手Go Gin 基于Go语言开发的Web框架,本文介绍了各种路由的配置信息;包含各场景下请求参数的基本传入接收
后端·golang·go·restful·gin·goweb开发
ん贤1 天前
并发编程【深度解剖】
后端·go·并发