f
This commit is contained in:
@@ -25,8 +25,10 @@ func SendSmsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
|||||||
}
|
}
|
||||||
// 获取客户端真实 IP
|
// 获取客户端真实 IP
|
||||||
clientIP := getClientIP(r)
|
clientIP := getClientIP(r)
|
||||||
|
// 获取 User-Agent 用于判断微信环境
|
||||||
|
userAgent := r.Header.Get("User-Agent")
|
||||||
l := auth.NewSendSmsLogic(r.Context(), svcCtx)
|
l := auth.NewSendSmsLogic(r.Context(), svcCtx)
|
||||||
err := l.SendSms(&req, clientIP)
|
err := l.SendSms(&req, clientIP, userAgent)
|
||||||
result.HttpResult(r, w, nil, err)
|
result.HttpResult(r, w, nil, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,25 +35,25 @@ func NewSendSmsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SendSmsLo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *SendSmsLogic) SendSms(req *types.SendSmsReq, clientIP string) error {
|
func (l *SendSmsLogic) SendSms(req *types.SendSmsReq, clientIP string, userAgent string) error {
|
||||||
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
||||||
encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey)
|
encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "短信发送, 加密手机号失败: %v", err)
|
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "短信发送, 加密手机号失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. 滑块验证码校验(可选)
|
// 1. 滑块验证码校验(可选,支持微信环境跳过验证)
|
||||||
cfg := l.svcCtx.Config.Captcha
|
cfg := l.svcCtx.Config.Captcha
|
||||||
captchaResult := captcha.VerifyOptional(captcha.Config{
|
captchaResult := captcha.VerifyOptionalWithUserAgent(captcha.Config{
|
||||||
AccessKeyID: cfg.AccessKeyID,
|
AccessKeyID: cfg.AccessKeyID,
|
||||||
AccessKeySecret: cfg.AccessKeySecret,
|
AccessKeySecret: cfg.AccessKeySecret,
|
||||||
EndpointURL: cfg.EndpointURL,
|
EndpointURL: cfg.EndpointURL,
|
||||||
SceneID: cfg.SceneID,
|
SceneID: cfg.SceneID,
|
||||||
}, req.CaptchaVerifyParam)
|
}, req.CaptchaVerifyParam, userAgent)
|
||||||
|
|
||||||
if captchaResult.VerifyErr != nil {
|
if captchaResult.VerifyErr != nil {
|
||||||
return captchaResult.VerifyErr
|
return captchaResult.VerifyErr
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 防刷策略
|
// 2. 防刷策略
|
||||||
if captchaResult.Skipped {
|
if captchaResult.Skipped {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package captcha
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
@@ -26,7 +27,77 @@ type VerifyResult struct {
|
|||||||
VerifyErr error // 验证错误(如果有)
|
VerifyErr error // 验证错误(如果有)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifyOptional 可选验证阿里云验证码
|
// isWeChatUserAgent 检测是否为微信浏览器的 User-Agent
|
||||||
|
func isWeChatUserAgent(userAgent string) bool {
|
||||||
|
if userAgent == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ua := strings.ToLower(userAgent)
|
||||||
|
return strings.Contains(ua, "micromessenger") || strings.Contains(ua, "wechat")
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyOptionalWithUserAgent 可选验证阿里云验证码(支持微信环境跳过验证)
|
||||||
|
// 当 captchaVerifyParam 为空时返回 Skipped=true,由调用方决定后续处理
|
||||||
|
// 当 userAgent 为微信浏览器时,跳过验证返回 Verified=true
|
||||||
|
func VerifyOptionalWithUserAgent(cfg Config, captchaVerifyParam string, userAgent string) VerifyResult {
|
||||||
|
// 开发环境可跳过验证
|
||||||
|
if os.Getenv("ENV") == "development" {
|
||||||
|
return VerifyResult{Verified: true, Skipped: false}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 微信环境下跳过图形验证码校验
|
||||||
|
if isWeChatUserAgent(userAgent) {
|
||||||
|
return VerifyResult{Verified: true, Skipped: false}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 没有滑块验证码参数,报错提示
|
||||||
|
if captchaVerifyParam == "" {
|
||||||
|
return VerifyResult{VerifyErr: 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 {
|
||||||
|
return VerifyResult{VerifyErr: errors.Wrapf(err, "create aliyun captcha client error")}
|
||||||
|
}
|
||||||
|
|
||||||
|
req := &captcha20230305.VerifyIntelligentCaptchaRequest{
|
||||||
|
SceneId: tea.String(cfg.SceneID),
|
||||||
|
CaptchaVerifyParam: tea.String(captchaVerifyParam),
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.VerifyIntelligentCaptcha(req)
|
||||||
|
if err != nil {
|
||||||
|
return VerifyResult{VerifyErr: errors.Wrapf(err, "verify aliyun captcha error")}
|
||||||
|
}
|
||||||
|
|
||||||
|
if tea.BoolValue(resp.Body.Result.VerifyResult) {
|
||||||
|
return VerifyResult{Verified: true}
|
||||||
|
}
|
||||||
|
|
||||||
|
return VerifyResult{
|
||||||
|
VerifyErr: errors.Wrapf(xerr.NewErrMsg("图形验证码校验失败"), "aliyun captcha verify failed: code=%s, msg=%s",
|
||||||
|
tea.StringValue(resp.Body.Code), tea.StringValue(resp.Body.Message)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyWithUserAgent 验证阿里云验证码(必须提供验证码参数,支持微信环境跳过验证)
|
||||||
|
func VerifyWithUserAgent(cfg Config, captchaVerifyParam string, userAgent string) error {
|
||||||
|
result := VerifyOptionalWithUserAgent(cfg, captchaVerifyParam, userAgent)
|
||||||
|
if result.VerifyErr != nil {
|
||||||
|
return result.VerifyErr
|
||||||
|
}
|
||||||
|
if result.Skipped {
|
||||||
|
return errors.Wrapf(xerr.NewErrMsg("图形验证码校验失败"), "empty captchaVerifyParam")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyOptional 可选验证阿里云验证码(兼容旧接口,不判断 User-Agent)
|
||||||
// 当 captchaVerifyParam 为空时返回 Skipped=true,由调用方决定后续处理
|
// 当 captchaVerifyParam 为空时返回 Skipped=true,由调用方决定后续处理
|
||||||
func VerifyOptional(cfg Config, captchaVerifyParam string) VerifyResult {
|
func VerifyOptional(cfg Config, captchaVerifyParam string) VerifyResult {
|
||||||
// 开发环境可跳过验证
|
// 开发环境可跳过验证
|
||||||
@@ -69,7 +140,7 @@ func VerifyOptional(cfg Config, captchaVerifyParam string) VerifyResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify 验证阿里云验证码(必须提供验证码参数)
|
// Verify 验证阿里云验证码(必须提供验证码参数,兼容旧接口)
|
||||||
func Verify(cfg Config, captchaVerifyParam string) error {
|
func Verify(cfg Config, captchaVerifyParam string) error {
|
||||||
result := VerifyOptional(cfg, captchaVerifyParam)
|
result := VerifyOptional(cfg, captchaVerifyParam)
|
||||||
if result.VerifyErr != nil {
|
if result.VerifyErr != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user