Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/go-leo/api-signer
用于对外接口的通用签名认证包
https://github.com/go-leo/api-signer
Last synced: about 1 month ago
JSON representation
用于对外接口的通用签名认证包
- Host: GitHub
- URL: https://github.com/go-leo/api-signer
- Owner: go-leo
- Created: 2023-03-08T03:10:02.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2023-03-22T10:23:49.000Z (almost 2 years ago)
- Last Synced: 2024-06-20T16:45:45.427Z (6 months ago)
- Language: Go
- Size: 35.2 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# api-signer
用于对外接口的通用签名认证包## 使用
#### 客户端
```go
import apisigner "github.com/go-leo/api-signer"// 构建一个http请求
req, err := http.NewRequest(method, host+path, payload)
if err != nil {
panic(err)
}
// 在构建完请求后调用如下方法即可
err = apisigner.NewSigner(apisigner.NewDefaultLogger(apisigner.LogInfo)).
Client("cn-shanghai-1", "asset", *Credential).
SetAuthHeader(req)
if err != nil {
...
}
```#### 服务端
```go
import apisigner "github.com/go-leo/api-signer"
// 在认证中间件中调用如下方法
serverSigner := apisigner.NewSigner(slog).Server(
apiSignerExpireDuration,
func(ak string) (sk string) {
return "apiSignerAK"
},
func(nonce string) bool {
return true
},
),
err := serverSigner.Vaild(req)
if err != nil {
return nil, errors.WrapC(err, code.ErrInvalidAuthHeader)
}
```## 签名流程
### 一、获取 ak、sk
### 二、生成签名
**2.1 url参数排序并生成请求字符串**`rawQuery`(1) 按字典序对查询参数的键进行排序并构建`rawQuery`, 用户可以借助编程语言中的相关排序函数来实现这一功能,如 PHP 中的 ksort 函数
(2) 把排序好的请求参数格式化成“参数名称=参数值”的形式, 然后将格式化后的各个参数用"&"拼接在一起,如下:
`Action=DescribeInstances&InstanceIds.0=ins-09dx96dg&Limit=20&Nonce=11886&Offset=0&Region=ap-guangzhou&SecretId=AKIDz8krbsJ5yKBZQpn74WFkmLPx3*******&Timestamp=1465185768&Version=2017-03-12`
**2.2 body内容计算摘要**`bodyDigest`
使用 sha256 对请求body计算摘要,对其结果转化为十六进制,伪代码为:
``` bodyDigest = hex(sha256(body)) ```
**2.2 生成 `payload`**
请求方法、请求路径、请求排序字符串、请求body摘要通过 '\n' 组合,生成`payload`;
伪代码为:
``` payload = http.Method+ '\n' + http.Path + '\n' + rawQuery + '\n' + bodyDigest ```
**2.2 生成 `credential`**
``` credential = (x-ca-date的短格式,如:20060102) + '/' + regoin + '/' + ServiceName + "/" + "apisigner_request" ```
**2.3 生成签名内容`strToSign`**
将签名算法、nonce、date、credential、 通过 '\n' 组合, 生成`strToSign`;
伪代码为:
``` strToSign = APISIGNER-HMAC-SHA256 + '\n' + x-ca-nonce + '\n' + x-ca-date + '\n' + credential + '\n' + hex(sha256(payload)) ```
**2.4 生成签名 `signature`**
`APISIGNER`字符串+`SK` 进行组合作为密钥,`strToSign`作为内容,通过 `HMAC-SHA256`算法来生成签名;
伪代码为:
``` signature = HmacSha256([]byte("APISIGNER"+secret), []byte(stringToSign)) ```
### 三、设置头字段
(1) 通过第二步计算出来的 `credential`、`signature`,设置 `Authorization` 头字段
`Authorization` = "APISIGNER-HMAC-SHA256" + " Credential=" + AK + "/" + credential + ", " + "Signature=" + signature
(2) 设置 `x-ca-nonce`、 `x-ca-date` 头字段;
`x-ca-nonce` = 随机值(用于防止重放攻击)
`x-ca-date` = RFC 3986 格式的当前时间(如:20060102T150405Z,用于检查签名是否过期)
## 验证签名流程
校验认证头是否包含必要字段 -> 校验时间是否合法 -> 校验认签名是否合法 -> 校验nonce是否合法
因为 nonce 大部分分布式应用都是用db或者redis之内的工具存储,防止有人生成大量的nonce攻击,这里将在内存里的低开销操作放在前面