You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
81 lines
3.1 KiB
81 lines
3.1 KiB
// Package idverify 身份证二要素(姓名 + 身份证号)实名核验。
|
|
//
|
|
// 与其它 sys 子系统不同,本包**不是启动时初始化的单例**:核验服务配在后台
|
|
// 「第三方服务配置」里(类别 comm.SvcCatIdVerify),按应用作用域存在 svc_config,
|
|
// 调用时才解析出凭据。所以这里只提供无状态的工厂 + 接口,由业务侧每次带配置进来。
|
|
//
|
|
// ⚠️ 这类服务的凭据是**云账号主 AK/SK**,comm.IsServerOnlySvc 会保证它们
|
|
// 永不随 user_getthirdsvcs / user_getappconfig 下发给客户端。
|
|
package idverify
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// 服务商标识(与 console 内置模板 ThirdSvcTemplate.Provider 一致)。
|
|
const (
|
|
ProviderAliyun = "aliyun"
|
|
ProviderTencent = "tencent"
|
|
ProviderChuanglan = "chuanglan"
|
|
)
|
|
|
|
var (
|
|
// ErrUnsupportedProvider 配了本包不认识的服务商。
|
|
ErrUnsupportedProvider = errors.New("idverify: 不支持的服务商")
|
|
// ErrMissingCredential 服务商凭据字段缺失。
|
|
ErrMissingCredential = errors.New("idverify: 凭据字段缺失")
|
|
)
|
|
|
|
// Result 一次核验的结果。
|
|
//
|
|
// 注意区分两种"失败":
|
|
// - Matched=false 且 err=nil:服务商**明确判定不一致**(正常业务结果,已计费)。
|
|
// - err!=nil:调用本身失败(网络/鉴权/额度耗尽/参数被拒),**结论未知**,不能当作"不一致"。
|
|
//
|
|
// 把后者当成"不一致"会让用户在服务商欠费时看到"您填的信息有误",是最难排查的一类线上问题。
|
|
type Result struct {
|
|
Matched bool // 姓名与身份证号是否一致
|
|
BizCode string // 服务商返回的原始结果码(阿里 ResultObject.BizCode / 腾讯 Result / 创蓝 data.result),便于对账排查
|
|
Message string // 服务商返回的可读说明
|
|
}
|
|
|
|
// Verifier 一个已装配好凭据的核验客户端。
|
|
type Verifier interface {
|
|
// Verify 执行二要素核验。realname/idcardno 为明文,调用方负责不落库。
|
|
Verify(ctx context.Context, realname, idcardno string) (Result, error)
|
|
// Provider 返回服务商标识,用于落库记录来源。
|
|
Provider() string
|
|
}
|
|
|
|
// New 按服务商与字段表装配一个核验客户端。
|
|
// fields 来自 comm.ResolveSvcPlainFields 的解密结果(键名与 console 内置模板一致)。
|
|
func New(provider string, fields map[string]string) (Verifier, error) {
|
|
switch strings.TrimSpace(strings.ToLower(provider)) {
|
|
case ProviderAliyun:
|
|
return newAliyun(fields)
|
|
case ProviderTencent:
|
|
return newTencent(fields)
|
|
case ProviderChuanglan:
|
|
return newChuanglan(fields)
|
|
default:
|
|
return nil, fmt.Errorf("%w: %s", ErrUnsupportedProvider, provider)
|
|
}
|
|
}
|
|
|
|
// field 取字段并去空白;缺失返回空串。
|
|
func field(fields map[string]string, key string) string {
|
|
return strings.TrimSpace(fields[key])
|
|
}
|
|
|
|
// requireFields 校验必填凭据字段齐全,返回第一个缺失的字段名。
|
|
func requireFields(fields map[string]string, keys ...string) error {
|
|
for _, k := range keys {
|
|
if field(fields, k) == "" {
|
|
return fmt.Errorf("%w: %s", ErrMissingCredential, k)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|