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.
112 lines
4.0 KiB
112 lines
4.0 KiB
package idverify
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/aliyun/alibaba-cloud-sdk-go/sdk"
|
|
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/auth/credentials"
|
|
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/requests"
|
|
)
|
|
|
|
// 阿里云 实人认证 - 身份二要素核验 Id2MetaVerify
|
|
// 文档:https://help.aliyun.com/zh/id-verification/information-verification/developer-reference/vatsl9lfmbwe74iv
|
|
//
|
|
// Action Id2MetaVerify
|
|
// Version 2019-03-07
|
|
// Domain cloudauth.aliyuncs.com(也可用 cloudauth.cn-beijing / cn-shanghai.aliyuncs.com)
|
|
// 入参 ParamType(normal|sm2) / UserName(姓名) / IdentifyNum(身份证号)
|
|
// 出参 Code(200 成功) / Message / ResultObject.BizCode(1=一致,2=不一致)
|
|
const (
|
|
aliyunDefaultRegion = "cn-shanghai"
|
|
aliyunDefaultDomain = "cloudauth.aliyuncs.com"
|
|
aliyunAPIVersion = "2019-03-07"
|
|
aliyunAction = "Id2MetaVerify"
|
|
|
|
aliyunBizCodeMatched = "1" // 校验一致
|
|
aliyunBizCodeMismatch = "2" // 校验不一致
|
|
)
|
|
|
|
type aliyunVerifier struct {
|
|
client *sdk.Client
|
|
domain string
|
|
}
|
|
|
|
// aliyunResp 只取需要的字段;其余忽略。
|
|
type aliyunResp struct {
|
|
RequestId string `json:"RequestId"`
|
|
Code string `json:"Code"`
|
|
Message string `json:"Message"`
|
|
ResultObject struct {
|
|
BizCode string `json:"BizCode"`
|
|
} `json:"ResultObject"`
|
|
}
|
|
|
|
func newAliyun(fields map[string]string) (Verifier, error) {
|
|
if err := requireFields(fields, "access_key_id", "access_key_secret"); err != nil {
|
|
return nil, err
|
|
}
|
|
region := field(fields, "region")
|
|
if region == "" {
|
|
region = aliyunDefaultRegion
|
|
}
|
|
domain := field(fields, "domain")
|
|
if domain == "" {
|
|
domain = aliyunDefaultDomain
|
|
}
|
|
|
|
c := sdk.NewConfig()
|
|
c.HttpTransport = &http.Transport{IdleConnTimeout: 10 * time.Second}
|
|
c.Timeout = 10 * time.Second
|
|
cred := credentials.NewAccessKeyCredential(field(fields, "access_key_id"), field(fields, "access_key_secret"))
|
|
client, err := sdk.NewClientWithOptions(region, c, cred)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("idverify/aliyun: 初始化客户端失败: %w", err)
|
|
}
|
|
return &aliyunVerifier{client: client, domain: domain}, nil
|
|
}
|
|
|
|
func (v *aliyunVerifier) Provider() string { return ProviderAliyun }
|
|
|
|
func (v *aliyunVerifier) Verify(ctx context.Context, realname, idcardno string) (Result, error) {
|
|
req := requests.NewCommonRequest()
|
|
req.Method = http.MethodPost
|
|
// ⚠️ 必须显式设成 HTTPS:NewCommonRequest 默认走 HTTP,而 Cloudauth 强制 SSL,
|
|
// 用 HTTP 调会被拒并返回 InvalidProtocol.NeedSsl("lack of ssl protect"),
|
|
// 表象是一个笼统的 SDK.ServerError,很容易被误当成凭据或额度问题。
|
|
req.Scheme = "https"
|
|
req.Domain = v.domain
|
|
req.Version = aliyunAPIVersion
|
|
req.ApiName = aliyunAction
|
|
req.QueryParams["ParamType"] = "normal" // 明文传参;sm2 需另配国密公钥,当前不启用
|
|
req.QueryParams["UserName"] = strings.TrimSpace(realname)
|
|
req.QueryParams["IdentifyNum"] = strings.TrimSpace(idcardno)
|
|
|
|
resp, err := v.client.ProcessCommonRequest(req)
|
|
if err != nil {
|
|
return Result{}, fmt.Errorf("idverify/aliyun: 调用失败: %w", err)
|
|
}
|
|
body := resp.GetHttpContentString()
|
|
|
|
var r aliyunResp
|
|
if err := json.Unmarshal([]byte(body), &r); err != nil {
|
|
return Result{}, fmt.Errorf("idverify/aliyun: 响应解析失败: %w", err)
|
|
}
|
|
// Code 非 200 表示调用层面失败(鉴权/参数/额度),结论未知——绝不能当成"不一致"。
|
|
if r.Code != "200" {
|
|
return Result{}, fmt.Errorf("idverify/aliyun: 调用返回 Code=%s Message=%s RequestId=%s", r.Code, r.Message, r.RequestId)
|
|
}
|
|
switch r.ResultObject.BizCode {
|
|
case aliyunBizCodeMatched:
|
|
return Result{Matched: true, BizCode: r.ResultObject.BizCode, Message: r.Message}, nil
|
|
case aliyunBizCodeMismatch:
|
|
return Result{Matched: false, BizCode: r.ResultObject.BizCode, Message: r.Message}, nil
|
|
default:
|
|
// 文档只定义了 1/2;出现别的值说明接口有变更,按"结论未知"处理而不是默默判不一致。
|
|
return Result{}, fmt.Errorf("idverify/aliyun: 未知 BizCode=%q RequestId=%s", r.ResultObject.BizCode, r.RequestId)
|
|
}
|
|
}
|
|
|