add ali captcha
This commit is contained in:
@@ -51,10 +51,11 @@ type (
|
||||
|
||||
type (
|
||||
QueryServiceReq {
|
||||
Product string `path:"product"`
|
||||
Data string `json:"data" validate:"required"`
|
||||
AgentIdentifier string `json:"agent_identifier,optional"`
|
||||
App bool `json:"app,optional"`
|
||||
Product string `path:"product"`
|
||||
Data string `json:"data" validate:"required"`
|
||||
AgentIdentifier string `json:"agent_identifier,optional"`
|
||||
App bool `json:"app,optional"`
|
||||
CaptchaVerifyParam string `json:"captchaVerifyParam,optional"`
|
||||
}
|
||||
QueryServiceResp {
|
||||
Id string `json:"id"`
|
||||
|
||||
@@ -141,8 +141,26 @@ service main {
|
||||
|
||||
type (
|
||||
sendSmsReq {
|
||||
Mobile string `json:"mobile" validate:"required,mobile"`
|
||||
ActionType string `json:"actionType" validate:"required,oneof=login register query agentApply realName bindMobile"`
|
||||
Mobile string `json:"mobile" validate:"required,mobile"`
|
||||
ActionType string `json:"actionType" validate:"required,oneof=login register query agentApply realName bindMobile"`
|
||||
CaptchaVerifyParam string `json:"captchaVerifyParam"`
|
||||
}
|
||||
)
|
||||
|
||||
//============================> captcha v1 <============================
|
||||
@server (
|
||||
prefix: api/v1
|
||||
group: captcha
|
||||
)
|
||||
service main {
|
||||
@doc "get encrypted scene id for aliyun captcha"
|
||||
@handler getEncryptedSceneId
|
||||
post /captcha/encryptedSceneId returns (GetEncryptedSceneIdResp)
|
||||
}
|
||||
|
||||
type (
|
||||
GetEncryptedSceneIdResp {
|
||||
EncryptedSceneId string `json:"encryptedSceneId"`
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -17,6 +17,12 @@ VerifyCode:
|
||||
SignName: "天远查"
|
||||
TemplateCode: "SMS_302641455"
|
||||
ValidTime: 300
|
||||
Captcha:
|
||||
AccessKeyID: "LTAI5tKGB3TVJbMHSoZN3yr9"
|
||||
AccessKeySecret: "OCQ30GWp4yENMjmfOAaagksE18bp65"
|
||||
EndpointURL: "captcha.cn-shanghai.aliyuncs.com"
|
||||
SceneID: "wynt39to"
|
||||
EKey: "xdhf5JbWVmFXx+2K+6kBk2aH++GtQBEI8Gmzdeen90o="
|
||||
Encrypt:
|
||||
SecretKey: "ff83609b2b24fc73196aac3d3dfb874f"
|
||||
Alipay:
|
||||
|
||||
@@ -19,6 +19,16 @@ VerifyCode:
|
||||
SignName: "天远查"
|
||||
TemplateCode: "SMS_302641455"
|
||||
ValidTime: 300
|
||||
Captcha:
|
||||
# 建议与短信相同的 AccessKey,或单独为验证码创建子账号
|
||||
AccessKeyID: "LTAI5tKGB3TVJbMHSoZN3yr9"
|
||||
AccessKeySecret: "OCQ30GWp4yENMjmfOAaagksE18bp65"
|
||||
# 验证码服务 Endpoint,国内一般为 captcha.cn-shanghai.aliyuncs.com
|
||||
EndpointURL: "captcha.cn-shanghai.aliyuncs.com"
|
||||
# 阿里云控制台中该场景的 SceneId,请替换为真实值
|
||||
SceneID: "wynt39to"
|
||||
# 验证码控制台中的 ekey(通常为 Base64 字符串),用于生成 EncryptedSceneId
|
||||
EKey: "xdhf5JbWVmFXx+2K+6kBk2aH++GtQBEI8Gmzdeen90o="
|
||||
Encrypt:
|
||||
SecretKey: "ff83609b2b24fc73196aac3d3dfb874f"
|
||||
WestConfig:
|
||||
|
||||
@@ -11,6 +11,7 @@ type Config struct {
|
||||
CacheRedis cache.CacheConf
|
||||
JwtAuth JwtAuth // JWT 鉴权相关配置
|
||||
VerifyCode VerifyCode
|
||||
Captcha CaptchaConfig
|
||||
Encrypt Encrypt
|
||||
Alipay AlipayConfig
|
||||
Wxpay WxpayConfig
|
||||
@@ -45,6 +46,13 @@ type VerifyCode struct {
|
||||
TemplateCode string
|
||||
ValidTime int
|
||||
}
|
||||
type CaptchaConfig struct {
|
||||
AccessKeyID string
|
||||
AccessKeySecret string
|
||||
EndpointURL string
|
||||
SceneID string
|
||||
EKey string
|
||||
}
|
||||
type Encrypt struct {
|
||||
SecretKey string
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package captcha
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"tyc-server/app/main/api/internal/logic/captcha"
|
||||
"tyc-server/app/main/api/internal/svc"
|
||||
"tyc-server/common/result"
|
||||
)
|
||||
|
||||
func GetEncryptedSceneIdHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
l := captcha.NewGetEncryptedSceneIdLogic(r.Context(), svcCtx)
|
||||
resp, err := l.GetEncryptedSceneId()
|
||||
result.HttpResult(r, w, resp, err)
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
app "tyc-server/app/main/api/internal/handler/app"
|
||||
auth "tyc-server/app/main/api/internal/handler/auth"
|
||||
authorization "tyc-server/app/main/api/internal/handler/authorization"
|
||||
captcha "tyc-server/app/main/api/internal/handler/captcha"
|
||||
notification "tyc-server/app/main/api/internal/handler/notification"
|
||||
pay "tyc-server/app/main/api/internal/handler/pay"
|
||||
product "tyc-server/app/main/api/internal/handler/product"
|
||||
@@ -954,6 +955,18 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
|
||||
rest.WithPrefix("/api/v1"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
[]rest.Route{
|
||||
{
|
||||
// get encrypted scene id for aliyun captcha
|
||||
Method: http.MethodPost,
|
||||
Path: "/captcha/encryptedSceneId",
|
||||
Handler: captcha.GetEncryptedSceneIdHandler(serverCtx),
|
||||
},
|
||||
},
|
||||
rest.WithPrefix("/api/v1"),
|
||||
)
|
||||
|
||||
server.AddRoutes(
|
||||
[]rest.Route{
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"math/rand"
|
||||
"time"
|
||||
"tyc-server/common/xerr"
|
||||
"tyc-server/pkg/captcha"
|
||||
"tyc-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -35,6 +36,17 @@ func NewSendSmsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SendSmsLo
|
||||
}
|
||||
|
||||
func (l *SendSmsLogic) SendSms(req *types.SendSmsReq) error {
|
||||
// 图形验证码校验(开发环境可跳过)
|
||||
cfg := l.svcCtx.Config.Captcha
|
||||
if err := captcha.Verify(captcha.Config{
|
||||
AccessKeyID: cfg.AccessKeyID,
|
||||
AccessKeySecret: cfg.AccessKeySecret,
|
||||
EndpointURL: cfg.EndpointURL,
|
||||
SceneID: cfg.SceneID,
|
||||
}, req.CaptchaVerifyParam); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
secretKey := l.svcCtx.Config.Encrypt.SecretKey
|
||||
encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey)
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package captcha
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"tyc-server/app/main/api/internal/svc"
|
||||
"tyc-server/app/main/api/internal/types"
|
||||
"tyc-server/pkg/captcha"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type GetEncryptedSceneIdLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetEncryptedSceneIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetEncryptedSceneIdLogic {
|
||||
return &GetEncryptedSceneIdLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetEncryptedSceneIdLogic) GetEncryptedSceneId() (resp *types.GetEncryptedSceneIdResp, err error) {
|
||||
cfg := l.svcCtx.Config.Captcha
|
||||
encrypted, genErr := captcha.GenerateEncryptedSceneID(cfg.SceneID, cfg.EKey, 3600)
|
||||
if genErr != nil {
|
||||
// 记录日志,返回通用错误
|
||||
l.Errorf("generate encrypted scene id error: %+v", genErr)
|
||||
return nil, genErr
|
||||
}
|
||||
return &types.GetEncryptedSceneIdResp{
|
||||
EncryptedSceneId: encrypted,
|
||||
}, nil
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"tyc-server/common/ctxdata"
|
||||
"tyc-server/common/globalkey"
|
||||
"tyc-server/common/xerr"
|
||||
"tyc-server/pkg/captcha"
|
||||
"tyc-server/pkg/lzkit/crypto"
|
||||
"tyc-server/pkg/lzkit/validator"
|
||||
|
||||
@@ -109,7 +110,52 @@ var productHandlers = map[string]queryHandlerFunc{
|
||||
"toc_BankcardBlacklist": runVerifyBankBlackReq,
|
||||
}
|
||||
|
||||
// productHasSmsCode 表示该 product 解密后的请求结构体中是否包含必填短信验证码 Code。
|
||||
// 有 Code 的产品在「获取验证码」时已经做了滑块,这里不再强制要求 CaptchaVerifyParam。
|
||||
// 其他产品(无 Code)在查询时必须传并校验 CaptchaVerifyParam,防止跳过图形验证。
|
||||
func productHasSmsCode(product string) bool {
|
||||
switch product {
|
||||
case "marriage",
|
||||
"homeservice",
|
||||
"riskassessment",
|
||||
"companyinfo",
|
||||
"rentalinfo",
|
||||
"preloanbackgroundcheck",
|
||||
"backgroundcheck",
|
||||
"personalData",
|
||||
"toc_PersonalLawsuit",
|
||||
"toc_EnterpriseLawsuit",
|
||||
"toc_Marriage",
|
||||
"toc_PersonalMarriageStatus",
|
||||
"toc_MarriageStatusRegisterTime",
|
||||
"toc_MarriageStatusSupplement",
|
||||
"toc_MarriageStatusVerify",
|
||||
"toc_DualMarriageStatusRegisterTime",
|
||||
"toc_VehiclesUnderName",
|
||||
"toc_VehiclesUnderNamePlate":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (l *QueryServiceLogic) PreprocessLogic(req *types.QueryServiceReq, product string) (*types.QueryServiceResp, error) {
|
||||
// 无短信验证码 Code 的 product:查询前必须传并校验滑块,否则不允许跳过
|
||||
if !productHasSmsCode(product) {
|
||||
if req.CaptchaVerifyParam == "" {
|
||||
return nil, errors.Wrapf(xerr.NewErrMsg("请完成图形验证"), "product %s requires captcha", product)
|
||||
}
|
||||
cfg := l.svcCtx.Config.Captcha
|
||||
if err := captcha.Verify(captcha.Config{
|
||||
AccessKeyID: cfg.AccessKeyID,
|
||||
AccessKeySecret: cfg.AccessKeySecret,
|
||||
EndpointURL: cfg.EndpointURL,
|
||||
SceneID: cfg.SceneID,
|
||||
}, req.CaptchaVerifyParam); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
decryptData, err := l.DecryptData(req.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -38,7 +38,7 @@ func (l *MobileCodeLoginLogic) MobileCodeLogin(req *types.MobileCodeLoginReq) (r
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 加密手机号失败: %+v", err)
|
||||
}
|
||||
// 检查验证码(开发环境可跳过)
|
||||
// 短信验证码校验(开发环境可跳过)
|
||||
if os.Getenv("ENV") != "development" {
|
||||
redisKey := fmt.Sprintf("%s:%s", "login", encryptedMobile)
|
||||
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
|
||||
|
||||
@@ -1547,6 +1547,10 @@ type GetCommissionResp struct {
|
||||
List []Commission `json:"list"` // 查询列表
|
||||
}
|
||||
|
||||
type GetEncryptedSceneIdResp struct {
|
||||
EncryptedSceneId string `json:"encryptedSceneId"`
|
||||
}
|
||||
|
||||
type GetLinkDataReq struct {
|
||||
LinkIdentifier string `form:"link_identifier"`
|
||||
}
|
||||
@@ -2050,10 +2054,11 @@ type QueryRetryResp struct {
|
||||
}
|
||||
|
||||
type QueryServiceReq struct {
|
||||
Product string `path:"product"`
|
||||
Data string `json:"data" validate:"required"`
|
||||
AgentIdentifier string `json:"agent_identifier,optional"`
|
||||
App bool `json:"app,optional"`
|
||||
Product string `path:"product"`
|
||||
Data string `json:"data" validate:"required"`
|
||||
AgentIdentifier string `json:"agent_identifier,optional"`
|
||||
App bool `json:"app,optional"`
|
||||
CaptchaVerifyParam string `json:"captchaVerifyParam,optional"`
|
||||
}
|
||||
|
||||
type QueryServiceResp struct {
|
||||
@@ -2245,6 +2250,7 @@ type GetAppVersionResp struct {
|
||||
}
|
||||
|
||||
type SendSmsReq struct {
|
||||
Mobile string `json:"mobile" validate:"required,mobile"`
|
||||
ActionType string `json:"actionType" validate:"required,oneof=login register query agentApply realName bindMobile"`
|
||||
Mobile string `json:"mobile" validate:"required,mobile"`
|
||||
ActionType string `json:"actionType" validate:"required,oneof=login register query agentApply realName bindMobile"`
|
||||
CaptchaVerifyParam string `json:"captchaVerifyParam"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user