api/signer.go

114 lines
2.6 KiB
Go
Raw Permalink Normal View History

package api
import (
"context"
"errors"
"apigo.cc/go/safe"
)
// Signer 负责为请求附加签名信息
type Signer interface {
Sign(req *HttpRequest, config map[string]any) error
}
var signers = map[string]Signer{
"basic": &basicSigner{},
"bearer": &bearerSigner{},
}
var jsRunner func(ctx context.Context, code string, args map[string]any) (map[string]any, error)
// SetJSRunner 设置 JS 执行器钩子,由 go/js 引擎在启动时注入。
// 这避免了 api 模块直接依赖 go/js 产生的循环引用。
func SetJSRunner(runner func(context.Context, string, map[string]any) (map[string]any, error)) {
jsRunner = runner
}
// RegisterSigner 注册全局签名器
func RegisterSigner(name string, s Signer) {
signers[name] = s
}
// GetSigner 获取签名器
func GetSigner(name string) Signer {
return signers[name]
}
// jsSigner 包装 JS 代码为 Go Signer 接口
type jsSigner struct {
code string
}
func (s *jsSigner) Sign(req *HttpRequest, config map[string]any) error {
if jsRunner == nil {
return errors.New("jsRunner is not set, cannot execute js signer")
}
// 准备传递给 JS 的参数
args := map[string]any{
"method": req.Method,
"url": req.Url,
"payload": req.Payload,
"headers": req.headers,
"config": config,
}
// 执行 JS 签名逻辑
// 注意:这里默认使用 Background context除非底层能透传低代码环境中会由 js_export 注入正确的 ctx
res, err := jsRunner(context.Background(), s.code, args)
if err != nil {
return err
}
// 将结果(通常是修改后的 headers写回请求对象
if newHeaders, ok := res["headers"].(map[string]any); ok {
for k, v := range newHeaders {
req.SetHeader(k, v)
}
}
// 如果 JS 返回了新的 URL 或 Method也支持修改
if newUrl, ok := res["url"].(string); ok {
req.Url = newUrl
}
if newMethod, ok := res["method"].(string); ok {
req.Method = newMethod
}
return nil
}
// 快速应用签名
func sign(name string, req *HttpRequest, config map[string]any) error {
if name == "" {
return nil
}
s := GetSigner(name)
if s == nil {
return errors.New("signer not found: " + name)
}
return s.Sign(req, config)
}
// 内置标准签名器实现
type basicSigner struct{}
func (s *basicSigner) Sign(req *HttpRequest, config map[string]any) error {
req.SetHeader("Authorization", "Basic ", safe.Base64(config["username"], ":", config["password"]))
return nil
}
type bearerSigner struct{}
func (s *bearerSigner) Sign(req *HttpRequest, config map[string]any) error {
token := config["token"]
if token == nil {
token = config["key"]
}
req.SetHeader("Authorization", "Bearer ", token)
return nil
}