This commit is contained in:
Mrx
2026-06-09 16:20:44 +08:00
parent e7d462028e
commit 209f9630ad
6 changed files with 101 additions and 3 deletions

View File

@@ -1233,10 +1233,12 @@ type JRZQVKK6Req struct {
}
type FLXGHB4FReq struct {
IDCard string `json:"id_card" validate:"required,validIDCard"`
Name string `json:"name" validate:"required,min=1,validName"`
IDCard string `json:"id_card" validate:"required,validIDCard"`
Name string `json:"name" validate:"required,min=1,validName"`
AuthPDFBase64 string `json:"auth_pdf_base64" validate:"required,validAuthPDFBase64"`
}
type QYGLBH7YReq struct {
EntName string `json:"ent_name" validate:"required,min=1,validEnterpriseName"`
EntName string `json:"ent_name" validate:"required,min=1,validEnterpriseName"`
AuthPDFBase64 string `json:"auth_pdf_base64" validate:"required,validAuthPDFBase64"`
}

View File

@@ -425,6 +425,8 @@ func (s *FormConfigServiceImpl) parseValidationRules(validateTag string) string
frontendRules = append(frontendRules, "授权链接格式")
case rule == "validBase64Image":
frontendRules = append(frontendRules, "Base64图片格式JPG、BMP、PNG")
case rule == "validAuthPDFBase64":
frontendRules = append(frontendRules, "授权PDF Base64格式500KB以内")
case rule == "base64" || rule == "validBase64":
frontendRules = append(frontendRules, "Base64编码格式支持图片/PDF")
case strings.HasPrefix(rule, "oneof="):
@@ -534,6 +536,7 @@ func (s *FormConfigServiceImpl) generateFieldLabel(jsonTag string) string {
"plate_color": "车牌颜色",
"marital_type": "婚姻状况类型",
"auth_authorize_file_base64": "PDF授权文件Base64编码5MB以内",
"auth_pdf_base64": "授权PDF文件Base64编码500KB以内",
}
if label, exists := labelMap[jsonTag]; exists {
@@ -600,6 +603,7 @@ func (s *FormConfigServiceImpl) generateExampleValue(fieldType reflect.Type, jso
"plate_color": "0",
"marital_type": "10",
"auth_authorize_file_base64": "JVBERi0xLjQKJcTl8uXr...示例PDF的Base64编码",
"auth_pdf_base64": "JVBERi0xLjQKJcTl8uXr...示例PDF的Base64编码",
}
if example, exists := exampleMap[jsonTag]; exists {
@@ -675,6 +679,7 @@ func (s *FormConfigServiceImpl) generatePlaceholder(jsonTag string, fieldType st
"plate_color": "请输入车牌颜色",
"marital_type": "请选择婚姻状况类型",
"auth_authorize_file_base64": "请输入PDF文件的Base64编码字符串",
"auth_pdf_base64": "请输入授权PDF文件的Base64编码字符串",
}
if placeholder, exists := placeholderMap[jsonTag]; exists {
@@ -752,6 +757,7 @@ func (s *FormConfigServiceImpl) generateDescription(jsonTag string, validation s
"plate_color": "车牌颜色",
"marital_type": "婚姻状况类型10-未登记无登记记录20-已婚30-丧偶40-离异",
"auth_authorize_file_base64": "请输入PDF文件的Base64编码字符串",
"auth_pdf_base64": "授权PDF文件Base64编码500KB以内须为有效PDF格式",
}
if desc, exists := descMap[jsonTag]; exists {

View File

@@ -24,6 +24,10 @@ func ProcessFLXGHB4FRequest(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrInvalidParam, err)
}
if _, err := deps.HuiboService.SaveAuthPDFLocally(ctx, "FLXGHB4F", paramsDto.AuthPDFBase64, paramsDto.IDCard); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
// 使用 MD5 加密 name 和 idCard
// encryptedName := "MD5:" + huibo.MD5Encrypt(paramsDto.Name, deps.HuiboService.GetConfig().AppKey)
// encryptedIDCard := "MD5:" + huibo.MD5Encrypt(paramsDto.IDCard, deps.HuiboService.GetConfig().AppKey)

View File

@@ -24,6 +24,10 @@ func ProcessQYGLBH7YRequest(ctx context.Context, params []byte, deps *processors
return nil, errors.Join(processors.ErrInvalidParam, err)
}
if _, err := deps.HuiboService.SaveAuthPDFLocally(ctx, "QYGLBH7Y", paramsDto.AuthPDFBase64, paramsDto.EntName); err != nil {
return nil, errors.Join(processors.ErrInvalidParam, err)
}
reqdata := map[string]interface{}{
"companyName": paramsDto.EntName,
}

View File

@@ -16,6 +16,8 @@ import (
"io"
"mime/multipart"
"net/http"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
@@ -38,6 +40,8 @@ const (
headerOrderCode = "X-ORDER-CODE"
headerSecretIDHdr = "secretId"
headerAESKeyHdr = "aesKey"
defaultAuthPDFStorageDir = "storage/huibo-auth-pdf"
)
// 汇博常见状态码
@@ -362,6 +366,66 @@ func decodeAndValidatePDF(base64PDF string) ([]byte, error) {
return raw, nil
}
// SaveAuthPDFLocally 解码校验后将授权 PDF 留存到本地CallAPI2 等 JSON 接口仅留存,不上传汇博)
func (s *HuiboService) SaveAuthPDFLocally(ctx context.Context, apiCode, authPDFBase64, subjectKey string) (string, error) {
pdfBytes, err := decodeAndValidatePDF(authPDFBase64)
if err != nil {
return "", err
}
transactionID := "unknown_tx"
if v, ok := ctx.Value("transaction_id").(string); ok && strings.TrimSpace(v) != "" {
transactionID = strings.TrimSpace(v)
}
dir := filepath.Join(defaultAuthPDFStorageDir, strings.TrimSpace(apiCode))
if err := os.MkdirAll(dir, 0755); err != nil {
return "", fmt.Errorf("创建授权PDF存储目录失败: %w", err)
}
filename := fmt.Sprintf("%s_%s_%s.pdf",
sanitizeAuthPDFFilenamePart(transactionID),
sanitizeAuthPDFFilenamePart(subjectKey),
time.Now().Format("20060102_150405"),
)
fullPath := filepath.Join(dir, filename)
if err := os.WriteFile(fullPath, pdfBytes, 0644); err != nil {
return "", fmt.Errorf("写入授权PDF失败: %w", err)
}
if s.logger != nil {
s.logger.LogInfo(
"汇博授权PDF已本地留存",
zap.String("api_code", apiCode),
zap.String("transaction_id", transactionID),
zap.String("path", fullPath),
zap.Int("size_bytes", len(pdfBytes)),
)
}
return fullPath, nil
}
func sanitizeAuthPDFFilenamePart(s string) string {
s = strings.TrimSpace(s)
if s == "" {
return "unknown"
}
var b strings.Builder
for _, r := range s {
switch {
case r >= 'a' && r <= 'z', r >= 'A' && r <= 'Z', r >= '0' && r <= '9', r == '-', r == '_':
b.WriteRune(r)
default:
b.WriteRune('_')
}
}
result := b.String()
if len(result) > 48 {
result = result[:48]
}
return result
}
func generateSortedParam(m map[string]string) string {
keys := make([]string, 0, len(m))
for k, v := range m {

View File

@@ -10,6 +10,8 @@ import (
"time"
"github.com/go-playground/validator/v10"
"hyapi-server/internal/shared/pdfvalidate"
)
// RegisterCustomValidators 注册所有自定义验证器
@@ -104,6 +106,9 @@ func RegisterCustomValidators(validate *validator.Validate) {
// Base64编码格式验证器
validate.RegisterValidation("base64", validateBase64)
validate.RegisterValidation("validBase64", validateBase64)
// 汇博授权 PDF Base64 验证器(解码后校验 PDF 魔数与大小上限)
validate.RegisterValidation("validAuthPDFBase64", validateAuthPDFBase64)
}
// validatePhone 手机号验证
@@ -1037,3 +1042,16 @@ func validateBase64(fl validator.FieldLevel) bool {
_, err := base64.StdEncoding.DecodeString(base64Str)
return err == nil
}
// validateAuthPDFBase64 汇博授权 PDF Base64 验证器
func validateAuthPDFBase64(fl validator.FieldLevel) bool {
base64Str := strings.TrimSpace(fl.Field().String())
if base64Str == "" {
return true
}
raw, err := base64.StdEncoding.DecodeString(base64Str)
if err != nil {
return false
}
return pdfvalidate.ValidateDecodedPDFBinary(raw) == nil
}