2025-11-27 13:09:54 +08:00
|
|
|
package service
|
|
|
|
|
|
|
|
|
|
import (
|
2025-12-09 18:55:28 +08:00
|
|
|
"context"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"net/http"
|
|
|
|
|
"ycc-server/app/main/api/internal/config"
|
|
|
|
|
tianyuanapi "ycc-server/app/main/api/internal/service/tianyuanapi_sdk"
|
|
|
|
|
|
|
|
|
|
"github.com/tidwall/gjson"
|
2025-11-27 13:09:54 +08:00
|
|
|
)
|
|
|
|
|
type VerificationService struct {
|
|
|
|
|
c config.Config
|
|
|
|
|
tianyuanapi *tianyuanapi.Client
|
|
|
|
|
apiRequestService *ApiRequestService
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewVerificationService(c config.Config, tianyuanapi *tianyuanapi.Client, apiRequestService *ApiRequestService) *VerificationService {
|
|
|
|
|
return &VerificationService{
|
|
|
|
|
c: c,
|
|
|
|
|
tianyuanapi: tianyuanapi,
|
|
|
|
|
apiRequestService: apiRequestService,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 二要素
|
|
|
|
|
type TwoFactorVerificationRequest struct {
|
|
|
|
|
Name string
|
|
|
|
|
IDCard string
|
|
|
|
|
}
|
|
|
|
|
type TwoFactorVerificationResp struct {
|
|
|
|
|
Msg string `json:"msg"`
|
|
|
|
|
Success bool `json:"success"`
|
|
|
|
|
Code int `json:"code"`
|
|
|
|
|
Data *TwoFactorVerificationData `json:"data"` //
|
|
|
|
|
}
|
|
|
|
|
type TwoFactorVerificationData struct {
|
|
|
|
|
Birthday string `json:"birthday"`
|
|
|
|
|
Result int `json:"result"`
|
|
|
|
|
Address string `json:"address"`
|
|
|
|
|
OrderNo string `json:"orderNo"`
|
|
|
|
|
Sex string `json:"sex"`
|
|
|
|
|
Desc string `json:"desc"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 三要素
|
|
|
|
|
type ThreeFactorVerificationRequest struct {
|
|
|
|
|
Name string
|
|
|
|
|
IDCard string
|
|
|
|
|
Mobile string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// VerificationResult 定义校验结果结构体
|
|
|
|
|
type VerificationResult struct {
|
|
|
|
|
Passed bool
|
|
|
|
|
Err error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ValidationError 定义校验错误类型
|
|
|
|
|
type ValidationError struct {
|
|
|
|
|
Message string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e *ValidationError) Error() string {
|
|
|
|
|
return e.Message
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *VerificationService) TwoFactorVerification(request TwoFactorVerificationRequest) (*VerificationResult, error) {
|
|
|
|
|
resp, err := r.tianyuanapi.CallInterface("YYSYBE08", map[string]interface{}{
|
|
|
|
|
"name": request.Name,
|
|
|
|
|
"id_card": request.IDCard,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("请求失败: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
respBytes, err := json.Marshal(resp.Data)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("转换响应失败: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 使用gjson获取resultCode
|
|
|
|
|
resultCode := gjson.GetBytes(respBytes, "ctidRequest.ctidAuth.resultCode")
|
|
|
|
|
if !resultCode.Exists() {
|
|
|
|
|
return &VerificationResult{
|
|
|
|
|
Passed: false,
|
|
|
|
|
Err: &ValidationError{Message: "获取resultCode失败"},
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取resultCode的第一个字符
|
|
|
|
|
resultCodeStr := resultCode.String()
|
|
|
|
|
if len(resultCodeStr) == 0 {
|
|
|
|
|
return &VerificationResult{
|
|
|
|
|
Passed: false,
|
|
|
|
|
Err: &ValidationError{Message: "resultCode为空"},
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
firstChar := string(resultCodeStr[0])
|
|
|
|
|
if firstChar != "0" && firstChar != "5" {
|
|
|
|
|
return &VerificationResult{
|
|
|
|
|
Passed: false,
|
|
|
|
|
Err: &ValidationError{Message: "姓名与身份证不一致"},
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &VerificationResult{Passed: true, Err: nil}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *VerificationService) ThreeFactorVerification(request ThreeFactorVerificationRequest) (*VerificationResult, error) {
|
|
|
|
|
resp, err := r.tianyuanapi.CallInterface("YYSY09CD", map[string]interface{}{
|
|
|
|
|
"name": request.Name,
|
|
|
|
|
"id_card": request.IDCard,
|
|
|
|
|
"mobile_no": request.Mobile,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("请求失败: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
respBytes, err := json.Marshal(resp.Data)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("转换响应失败: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 解析data.code
|
|
|
|
|
code := gjson.GetBytes(respBytes, "code")
|
|
|
|
|
if !code.Exists() {
|
|
|
|
|
return &VerificationResult{
|
|
|
|
|
Passed: false,
|
|
|
|
|
Err: &ValidationError{Message: "身份信息异常"},
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
codeStr := code.String()
|
|
|
|
|
switch codeStr {
|
|
|
|
|
case "1000":
|
|
|
|
|
// 一致
|
|
|
|
|
return &VerificationResult{Passed: true, Err: nil}, nil
|
|
|
|
|
case "1001":
|
|
|
|
|
// 不一致
|
|
|
|
|
return &VerificationResult{
|
|
|
|
|
Passed: false,
|
|
|
|
|
Err: &ValidationError{Message: "姓名、证件号、手机号信息不一致"},
|
|
|
|
|
}, nil
|
|
|
|
|
default:
|
|
|
|
|
// 其他异常
|
|
|
|
|
return &VerificationResult{
|
|
|
|
|
Passed: false,
|
|
|
|
|
Err: &ValidationError{Message: "身份信息异常"},
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-12-09 18:55:28 +08:00
|
|
|
|
|
|
|
|
// GetWechatH5OpenID 通过code获取微信H5 OpenID
|
|
|
|
|
func (r *VerificationService) GetWechatH5OpenID(ctx context.Context, code string) (string, error) {
|
|
|
|
|
appID := r.c.WechatH5.AppID
|
|
|
|
|
appSecret := r.c.WechatH5.AppSecret
|
|
|
|
|
url := fmt.Sprintf("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code", appID, appSecret, code)
|
|
|
|
|
resp, err := http.Get(url)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
var data struct {
|
|
|
|
|
Openid string `json:"openid"`
|
|
|
|
|
}
|
|
|
|
|
if err := json.Unmarshal(body, &data); err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
if data.Openid == "" {
|
|
|
|
|
return "", fmt.Errorf("openid为空")
|
|
|
|
|
}
|
|
|
|
|
return data.Openid, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetWechatMiniOpenID 通过code获取微信小程序 OpenID
|
|
|
|
|
func (r *VerificationService) GetWechatMiniOpenID(ctx context.Context, code string) (string, error) {
|
|
|
|
|
appID := r.c.WechatMini.AppID
|
|
|
|
|
appSecret := r.c.WechatMini.AppSecret
|
|
|
|
|
url := fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code", appID, appSecret, code)
|
|
|
|
|
resp, err := http.Get(url)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
var data struct {
|
|
|
|
|
Openid string `json:"openid"`
|
|
|
|
|
}
|
|
|
|
|
if err := json.Unmarshal(body, &data); err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
if data.Openid == "" {
|
|
|
|
|
return "", fmt.Errorf("openid为空")
|
|
|
|
|
}
|
|
|
|
|
return data.Openid, nil
|
|
|
|
|
}
|