package idverify import ( "context" "encoding/json" "fmt" "strings" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" tchttp "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/http" "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" ) // 腾讯云 人脸核身 - 身份证二要素核验 IdCardVerification // 文档:https://cloud.tencent.com/document/product/1007/33188 // // Action IdCardVerification // Version 2018-03-01 // Service faceid(域名 faceid.tencentcloudapi.com) // 入参 Name(姓名) / IdCard(身份证号) // 出参 Result / Description // Result "0" = 一致 // Result "-1" = 不一致 // Result "-2".."-7" = 各类错误(格式错误、查无此人、系统升级、当日调用超限等) // // 走 common 包的通用调用(NewCommonClient + CommonRequest),不额外引入 faceid 子包依赖。 const ( tencentService = "faceid" tencentAPIVersion = "2018-03-01" tencentAction = "IdCardVerification" tencentResultMatched = "0" // 一致 tencentResultMismatch = "-1" // 不一致 ) type tencentVerifier struct { client *common.Client } // tencentResp 腾讯云响应外层统一包了一层 Response。 type tencentResp struct { Response struct { Result string `json:"Result"` Description string `json:"Description"` RequestId string `json:"RequestId"` Error *struct { Code string `json:"Code"` Message string `json:"Message"` } `json:"Error"` } `json:"Response"` } func newTencent(fields map[string]string) (Verifier, error) { if err := requireFields(fields, "secret_id", "secret_key"); err != nil { return nil, err } cred := common.NewCredential(field(fields, "secret_id"), field(fields, "secret_key")) cpf := profile.NewClientProfile() cpf.HttpProfile.ReqMethod = "POST" cpf.HttpProfile.ReqTimeout = 10 // 本接口不需要传 Region(文档明示),留空即可;仍允许后台配置以备将来变化。 return &tencentVerifier{client: common.NewCommonClient(cred, field(fields, "region"), cpf)}, nil } func (v *tencentVerifier) Provider() string { return ProviderTencent } func (v *tencentVerifier) Verify(ctx context.Context, realname, idcardno string) (Result, error) { req := tchttp.NewCommonRequest(tencentService, tencentAPIVersion, tencentAction) if err := req.SetActionParameters(map[string]interface{}{ "Name": strings.TrimSpace(realname), "IdCard": strings.TrimSpace(idcardno), }); err != nil { return Result{}, fmt.Errorf("idverify/tencent: 组装请求失败: %w", err) } resp := tchttp.NewCommonResponse() if err := v.client.Send(req, resp); err != nil { return Result{}, fmt.Errorf("idverify/tencent: 调用失败: %w", err) } var r tencentResp if err := json.Unmarshal(resp.GetBody(), &r); err != nil { return Result{}, fmt.Errorf("idverify/tencent: 响应解析失败: %w", err) } if e := r.Response.Error; e != nil && e.Code != "" { return Result{}, fmt.Errorf("idverify/tencent: 调用返回错误 Code=%s Message=%s RequestId=%s", e.Code, e.Message, r.Response.RequestId) } switch r.Response.Result { case tencentResultMatched: return Result{Matched: true, BizCode: r.Response.Result, Message: r.Response.Description}, nil case tencentResultMismatch: return Result{Matched: false, BizCode: r.Response.Result, Message: r.Response.Description}, nil default: // -2..-7 是"查无此人/格式错误/当日超限/系统升级"等,结论未知,不能判成"不一致", // 否则服务商当日额度用尽时,所有用户都会看到"信息有误"。 return Result{}, fmt.Errorf("idverify/tencent: 核验未得出结论 Result=%s Description=%s RequestId=%s", r.Response.Result, r.Response.Description, r.Response.RequestId) } }