Files
ycc-proxy-server/pkg/captcha/aliyun.go
2026-02-28 12:18:25 +08:00

108 lines
3.4 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 captcha
import (
"context"
"os"
"strings"
captcha20230305 "github.com/alibabacloud-go/captcha-20230305/client"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
"github.com/alibabacloud-go/tea/tea"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
"ycc-server/common/xerr"
)
// 用于在 context 中传递 User-Agent 的 key仅本包读取
type ctxKey struct{}
var userAgentCtxKey = &ctxKey{}
// WithUserAgent 将 User-Agent 写入 context供 Verify 判断是否微信环境
func WithUserAgent(ctx context.Context, userAgent string) context.Context {
if ctx == nil {
return ctx
}
return context.WithValue(ctx, userAgentCtxKey, userAgent)
}
// isWechatUserAgent 判断是否为微信内置浏览器含小程序、H5
func isWechatUserAgent(ua string) bool {
return strings.Contains(ua, "MicroMessenger")
}
// Config 验证码配置
type Config struct {
AccessKeyID string
AccessKeySecret string
EndpointURL string
SceneID string
}
// Verify 验证阿里云滑块验证码。若 ctx 中带有 User-Agent 且为微信环境则跳过验证(默认成功)。
func Verify(ctx context.Context, cfg Config, captchaVerifyParam string) error {
// 开发环境跳过验证
if os.Getenv("ENV") == "development" {
logx.Info("[Captcha] 开发环境,跳过验证码校验")
return nil
}
// 微信环境(内置浏览器/小程序)跳过图形验证码,不要求 captchaVerifyParam
if ua, ok := ctx.Value(userAgentCtxKey).(string); ok && ua != "" && isWechatUserAgent(ua) {
logx.Info("[Captcha] 微信环境,跳过图形验证码校验")
return nil
}
// 检查参数
if captchaVerifyParam == "" {
return errors.Wrapf(xerr.NewErrMsg("图形验证码校验失败"), "empty captchaVerifyParam")
}
// 创建客户端配置
clientCfg := &openapi.Config{
AccessKeyId: tea.String(cfg.AccessKeyID),
AccessKeySecret: tea.String(cfg.AccessKeySecret),
}
clientCfg.Endpoint = tea.String(cfg.EndpointURL)
// 创建客户端
client, err := captcha20230305.NewClient(clientCfg)
if err != nil {
logx.Errorf("[Captcha] 创建阿里云验证码客户端失败: %+v", err)
// 客户端创建失败时,为了不影响业务可用性,记录日志但视为通过
// 可根据风险偏好调整此策略
return nil
}
// 构建验证请求
req := &captcha20230305.VerifyIntelligentCaptchaRequest{
SceneId: tea.String(cfg.SceneID),
CaptchaVerifyParam: tea.String(captchaVerifyParam),
}
// 调用验证接口
resp, err := client.VerifyIntelligentCaptcha(req)
if err != nil {
logx.Errorf("[Captcha] 调用阿里云验证码接口失败: %+v", err)
// 接口调用失败时,为了不影响业务可用性,记录日志但视为通过
// 可根据风险偏好调整此策略
return nil
}
// 检查验证结果
if resp == nil || resp.Body == nil || resp.Body.Result == nil {
logx.Errorf("[Captcha] 阿里云验证码响应异常: resp=%+v", resp)
return errors.Wrapf(xerr.NewErrMsg("图形验证码校验失败"), "invalid response")
}
if tea.BoolValue(resp.Body.Result.VerifyResult) {
logx.Info("[Captcha] 验证码校验通过")
return nil
}
// 验证失败
logx.Errorf("[Captcha] 验证码校验失败: code=%s", tea.StringValue(resp.Body.Result.VerifyCode))
return errors.Wrapf(xerr.NewErrMsg("图形验证码校验失败"), "verify failed: %s", tea.StringValue(resp.Body.Result.VerifyCode))
}