您的当前位置:首页正文

go-zero api 签名前后端详解

2024-11-25 来源:个人技术集锦

签名这部分只描述了怎么开启签名,但是后续配置和前端怎么访问都没有写。这部分我翻了源码踩了很多坑终于调试通了,在这里记录分享下,避免大家踩坑。

1. 大家先按照官网编写.api文件,生成代码

syntax = "v1"

type (
    SignDemoReq {
        Msg string `json:"msg"`
    }
    SignDemoResp {
        Msg string `json:"msg"`
    }
)

@server (
    signature: true // 通过 signature 关键字开启签名功能
)
service sign-api {
    @handler SignDemo
    post /sign/demo (SignDemoReq) returns (SignDemoResp)
}

2. 生成RSA公私钥

这个生成方法很多,百度搜索在线rsa , 很多网站可以生成,比如
拿到公私钥后新建文件。放到项目下。

3. 配置文件

Signature:
  Strict: true
  Expiry: 1h
  PrivateKeys:
    - Fingerprint: "xxxFingerprintxxx"
      KeyFile: ./data/id_rsa

到这个一步后端就完成了

4. 前端密钥生成

开启 Strict: true 后前端需要生成一个密钥放到 请求头X-Content-Security
这个密钥分成3部分 key secret signature,然后将这个三部分用; 连接起来

<key>;<secret>;<signature>
4.1 key

key的值就是配置文件中配置的Fingerprint的值,所以第一部分key为

const key = xxxFingerprintxxx
4.2 secret

待加密字符串生成方式

type=<type>;key=<key>;time=<time>

type 0 或者 1
key 是Fingerprint的值base64后的结果
time 时间戳 秒
在将这个字符串用rsa的公钥进行加密, js demo 如下

import Jsencrypt from 'jsencrypt';

const key = "xxxFingerprintxxx"
const time = (Date.now() / 1000).toFixed()
let secret = `type=0;key=${btoa(key)};time=${time}`

let sign = new Jsencrypt()

sign.setPublicKey(`-----BEGIN PUBLIC KEY-----
xxxxxxxxxxxxxx这是是公钥xxxxxxxxxxxxxxxxxxxx
-----END PUBLIC KEY-----`)

secret = sign.encrypt(secret)

// secret 就是第二部分了
4.3 signature

go-zero 源码

signContent := strings.Join([]string{
		securityHeader.Timestamp,
		r.Method,
		reqPath,
		reqQuery,
		computeBodySignature(r),
	}, "\n")
	
actualSignature := codec.HmacBase64(securityHeader.Key, signContent)

将 上面的 时间戳, 请求方法(大写), 请求路径(不包含host),请求参数,和sha256(请求体) 用 \n 拼接起来
在用HmacSHA256进行加解密,这里加密key还是用Fingerprint的值,在对加密后的结果进行base64 编码,就得到了signature.
这里有两个大坑,请求参数和请求体和其他参数为空的情况下不能省略 \n ,也就是说拼接的这个字符串必须有 4个 \n。 第二个大坑,如果请求体为空也要进行sha256,对空字符串进行sha256结果是 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
js demo

import CryptoJS from 'crypto-js';
let signature = `${time}\nGET\n/api/me/userinfo\n\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`
const hash = CryptoJS.HmacSHA256(signature, key)
signature = CryptoJS.enc.Base64.stringify(hash)
console.log(signature);

最后的结果

console.log(`key=${key};secret=${secret};signature=${signature}`);
显示全文