api/signer.go

114 lines
2.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}