114 lines
2.6 KiB
Go
114 lines
2.6 KiB
Go
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
|
||
}
|