f
This commit is contained in:
@@ -1235,8 +1235,10 @@ type JRZQVKK6Req struct {
|
|||||||
type FLXGHB4FReq struct {
|
type FLXGHB4FReq struct {
|
||||||
IDCard string `json:"id_card" validate:"required,validIDCard"`
|
IDCard string `json:"id_card" validate:"required,validIDCard"`
|
||||||
Name string `json:"name" validate:"required,min=1,validName"`
|
Name string `json:"name" validate:"required,min=1,validName"`
|
||||||
|
AuthPDFBase64 string `json:"auth_pdf_base64" validate:"required,validAuthPDFBase64"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type QYGLBH7YReq struct {
|
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, "授权链接格式")
|
frontendRules = append(frontendRules, "授权链接格式")
|
||||||
case rule == "validBase64Image":
|
case rule == "validBase64Image":
|
||||||
frontendRules = append(frontendRules, "Base64图片格式(JPG、BMP、PNG)")
|
frontendRules = append(frontendRules, "Base64图片格式(JPG、BMP、PNG)")
|
||||||
|
case rule == "validAuthPDFBase64":
|
||||||
|
frontendRules = append(frontendRules, "授权PDF Base64格式(500KB以内)")
|
||||||
case rule == "base64" || rule == "validBase64":
|
case rule == "base64" || rule == "validBase64":
|
||||||
frontendRules = append(frontendRules, "Base64编码格式(支持图片/PDF)")
|
frontendRules = append(frontendRules, "Base64编码格式(支持图片/PDF)")
|
||||||
case strings.HasPrefix(rule, "oneof="):
|
case strings.HasPrefix(rule, "oneof="):
|
||||||
@@ -534,6 +536,7 @@ func (s *FormConfigServiceImpl) generateFieldLabel(jsonTag string) string {
|
|||||||
"plate_color": "车牌颜色",
|
"plate_color": "车牌颜色",
|
||||||
"marital_type": "婚姻状况类型",
|
"marital_type": "婚姻状况类型",
|
||||||
"auth_authorize_file_base64": "PDF授权文件Base64编码(5MB以内)",
|
"auth_authorize_file_base64": "PDF授权文件Base64编码(5MB以内)",
|
||||||
|
"auth_pdf_base64": "授权PDF文件Base64编码(500KB以内)",
|
||||||
}
|
}
|
||||||
|
|
||||||
if label, exists := labelMap[jsonTag]; exists {
|
if label, exists := labelMap[jsonTag]; exists {
|
||||||
@@ -600,6 +603,7 @@ func (s *FormConfigServiceImpl) generateExampleValue(fieldType reflect.Type, jso
|
|||||||
"plate_color": "0",
|
"plate_color": "0",
|
||||||
"marital_type": "10",
|
"marital_type": "10",
|
||||||
"auth_authorize_file_base64": "JVBERi0xLjQKJcTl8uXr...(示例PDF的Base64编码)",
|
"auth_authorize_file_base64": "JVBERi0xLjQKJcTl8uXr...(示例PDF的Base64编码)",
|
||||||
|
"auth_pdf_base64": "JVBERi0xLjQKJcTl8uXr...(示例PDF的Base64编码)",
|
||||||
}
|
}
|
||||||
|
|
||||||
if example, exists := exampleMap[jsonTag]; exists {
|
if example, exists := exampleMap[jsonTag]; exists {
|
||||||
@@ -675,6 +679,7 @@ func (s *FormConfigServiceImpl) generatePlaceholder(jsonTag string, fieldType st
|
|||||||
"plate_color": "请输入车牌颜色",
|
"plate_color": "请输入车牌颜色",
|
||||||
"marital_type": "请选择婚姻状况类型",
|
"marital_type": "请选择婚姻状况类型",
|
||||||
"auth_authorize_file_base64": "请输入PDF文件的Base64编码字符串",
|
"auth_authorize_file_base64": "请输入PDF文件的Base64编码字符串",
|
||||||
|
"auth_pdf_base64": "请输入授权PDF文件的Base64编码字符串",
|
||||||
}
|
}
|
||||||
|
|
||||||
if placeholder, exists := placeholderMap[jsonTag]; exists {
|
if placeholder, exists := placeholderMap[jsonTag]; exists {
|
||||||
@@ -752,6 +757,7 @@ func (s *FormConfigServiceImpl) generateDescription(jsonTag string, validation s
|
|||||||
"plate_color": "车牌颜色",
|
"plate_color": "车牌颜色",
|
||||||
"marital_type": "婚姻状况类型:10-未登记(无登记记录),20-已婚,30-丧偶,40-离异",
|
"marital_type": "婚姻状况类型:10-未登记(无登记记录),20-已婚,30-丧偶,40-离异",
|
||||||
"auth_authorize_file_base64": "请输入PDF文件的Base64编码字符串",
|
"auth_authorize_file_base64": "请输入PDF文件的Base64编码字符串",
|
||||||
|
"auth_pdf_base64": "授权PDF文件Base64编码(500KB以内,须为有效PDF格式)",
|
||||||
}
|
}
|
||||||
|
|
||||||
if desc, exists := descMap[jsonTag]; exists {
|
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)
|
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
|
// 使用 MD5 加密 name 和 idCard
|
||||||
// encryptedName := "MD5:" + huibo.MD5Encrypt(paramsDto.Name, deps.HuiboService.GetConfig().AppKey)
|
// encryptedName := "MD5:" + huibo.MD5Encrypt(paramsDto.Name, deps.HuiboService.GetConfig().AppKey)
|
||||||
// encryptedIDCard := "MD5:" + huibo.MD5Encrypt(paramsDto.IDCard, 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)
|
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{}{
|
reqdata := map[string]interface{}{
|
||||||
"companyName": paramsDto.EntName,
|
"companyName": paramsDto.EntName,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -38,6 +40,8 @@ const (
|
|||||||
headerOrderCode = "X-ORDER-CODE"
|
headerOrderCode = "X-ORDER-CODE"
|
||||||
headerSecretIDHdr = "secretId"
|
headerSecretIDHdr = "secretId"
|
||||||
headerAESKeyHdr = "aesKey"
|
headerAESKeyHdr = "aesKey"
|
||||||
|
|
||||||
|
defaultAuthPDFStorageDir = "storage/huibo-auth-pdf"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 汇博常见状态码
|
// 汇博常见状态码
|
||||||
@@ -362,6 +366,66 @@ func decodeAndValidatePDF(base64PDF string) ([]byte, error) {
|
|||||||
return raw, nil
|
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 {
|
func generateSortedParam(m map[string]string) string {
|
||||||
keys := make([]string, 0, len(m))
|
keys := make([]string, 0, len(m))
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
|
|
||||||
|
"hyapi-server/internal/shared/pdfvalidate"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RegisterCustomValidators 注册所有自定义验证器
|
// RegisterCustomValidators 注册所有自定义验证器
|
||||||
@@ -104,6 +106,9 @@ func RegisterCustomValidators(validate *validator.Validate) {
|
|||||||
// Base64编码格式验证器
|
// Base64编码格式验证器
|
||||||
validate.RegisterValidation("base64", validateBase64)
|
validate.RegisterValidation("base64", validateBase64)
|
||||||
validate.RegisterValidation("validBase64", validateBase64)
|
validate.RegisterValidation("validBase64", validateBase64)
|
||||||
|
|
||||||
|
// 汇博授权 PDF Base64 验证器(解码后校验 PDF 魔数与大小上限)
|
||||||
|
validate.RegisterValidation("validAuthPDFBase64", validateAuthPDFBase64)
|
||||||
}
|
}
|
||||||
|
|
||||||
// validatePhone 手机号验证
|
// validatePhone 手机号验证
|
||||||
@@ -1037,3 +1042,16 @@ func validateBase64(fl validator.FieldLevel) bool {
|
|||||||
_, err := base64.StdEncoding.DecodeString(base64Str)
|
_, err := base64.StdEncoding.DecodeString(base64Str)
|
||||||
return err == nil
|
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