f
This commit is contained in:
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user