新增代理实名认证和授权
This commit is contained in:
122
app/user/cmd/api/internal/logic/auth/getfaceverifyresultlogic.go
Normal file
122
app/user/cmd/api/internal/logic/auth/getfaceverifyresultlogic.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"qnc-server/common/xerr"
|
||||
|
||||
"github.com/bytedance/sonic"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"qnc-server/app/user/cmd/api/internal/svc"
|
||||
"qnc-server/app/user/cmd/api/internal/types"
|
||||
"qnc-server/app/user/model"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type GetFaceVerifyResultLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewGetFaceVerifyResultLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetFaceVerifyResultLogic {
|
||||
return &GetFaceVerifyResultLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *GetFaceVerifyResultLogic) GetFaceVerifyResult(req *types.GetFaceVerifyResultReq) (resp *types.GetFaceVerifyResultResp, err error) {
|
||||
// 1. 查询认证明细
|
||||
face, err := l.svcCtx.AuthorizationFaceModel.FindOneByCertifyId(l.ctx, req.CertifyId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询认证明细失败: %v", err)
|
||||
}
|
||||
if face == nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询认证明细为空")
|
||||
}
|
||||
|
||||
// 2. 查询主授权(如后续需要可用)
|
||||
auth, err := l.svcCtx.AuthorizationModel.FindOne(l.ctx, face.AuthorizationId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询授权主表失败: %v", err)
|
||||
}
|
||||
|
||||
// 3. 判断人脸认证明细和主授权状态,若均已是"success",则直接返回通过
|
||||
if (face.Status == model.AuthorizationFaceStatusSuccess) && (auth.Status == model.AuthorizationStatusSuccess) {
|
||||
return &types.GetFaceVerifyResultResp{
|
||||
OrderID: auth.OrderId,
|
||||
Passed: true,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 4. 调用阿里云接口查询认证结果
|
||||
describeResp, err := l.svcCtx.CloudAuthService.DescribeFaceVerify(req.CertifyId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "校验人脸识别结果失败: %v", err)
|
||||
}
|
||||
|
||||
// 5. 判断认证状态并更新(使用事务)
|
||||
if describeResp.Passed {
|
||||
// 使用事务更新状态
|
||||
err = l.svcCtx.AuthorizationModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
order, err := l.svcCtx.OrderModel.FindOne(ctx, auth.OrderId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "查询订单失败")
|
||||
}
|
||||
redisKey := fmt.Sprintf(types.QueryCacheKey, order.UserId, order.OrderNo)
|
||||
cache, cacheErr := l.svcCtx.Redis.GetCtx(ctx, redisKey)
|
||||
if cacheErr != nil {
|
||||
return fmt.Errorf("获取缓存内容失败: %+v", cacheErr)
|
||||
}
|
||||
var data types.QueryCacheLoad
|
||||
err = sonic.Unmarshal([]byte(cache), &data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("解析缓存内容失败: %+v", err)
|
||||
}
|
||||
// 插入新queryModel
|
||||
query := &model.Query{
|
||||
OrderId: auth.OrderId,
|
||||
UserId: auth.UserId,
|
||||
ProductId: order.ProductId,
|
||||
QueryParams: data.Params,
|
||||
QueryState: "pending",
|
||||
}
|
||||
_, insertQueryErr := l.svcCtx.QueryModel.Insert(ctx, session, query)
|
||||
if insertQueryErr != nil {
|
||||
return errors.Wrapf(insertQueryErr, "保存查询失败")
|
||||
}
|
||||
// 更新主授权状态
|
||||
auth.Status = model.AuthorizationStatusSuccess
|
||||
_, err = l.svcCtx.AuthorizationModel.Update(ctx, session, auth)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "更新授权状态失败")
|
||||
}
|
||||
// 更新人脸认证明细状态
|
||||
face.Status = model.AuthorizationFaceStatusSuccess
|
||||
_, err = l.svcCtx.AuthorizationFaceModel.Update(ctx, session, face)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "更新人脸认证状态失败")
|
||||
}
|
||||
if asyncErr := l.svcCtx.AsynqService.SendQueryTask(auth.OrderId); asyncErr != nil {
|
||||
logx.Errorf("异步任务调度失败: %v", asyncErr)
|
||||
return asyncErr
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "更新认证状态失败: %v", err)
|
||||
}
|
||||
}
|
||||
// 6. 返回resp(resp.Passed := describeResp.Passed)和err(如有)
|
||||
resp = &types.GetFaceVerifyResultResp{
|
||||
OrderID: auth.OrderId,
|
||||
Passed: describeResp.Passed,
|
||||
AuthType: auth.AuthType.Int64,
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
134
app/user/cmd/api/internal/logic/auth/initfaceverifylogic.go
Normal file
134
app/user/cmd/api/internal/logic/auth/initfaceverifylogic.go
Normal file
@@ -0,0 +1,134 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"qnc-server/app/user/cmd/api/internal/svc"
|
||||
"qnc-server/app/user/cmd/api/internal/types"
|
||||
"qnc-server/app/user/model"
|
||||
"qnc-server/common/xerr"
|
||||
"qnc-server/pkg/core/aliyun/cloudauth"
|
||||
"qnc-server/pkg/lzkit/crypto"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
||||
)
|
||||
|
||||
type InitFaceVerifyLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewInitFaceVerifyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *InitFaceVerifyLogic {
|
||||
return &InitFaceVerifyLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
// 生成带前缀的随机OuterOrderNo(阿里云人脸验证单号)
|
||||
func genOuterOrderNo() string {
|
||||
prefix := "FACE_"
|
||||
timestamp := time.Now().UnixNano()
|
||||
randNum := rand.Intn(1000000)
|
||||
return prefix + strconv.FormatInt(timestamp, 10) + strconv.Itoa(randNum)
|
||||
}
|
||||
|
||||
func (l *InitFaceVerifyLogic) InitFaceVerify(req *types.InitFaceVerifyReq) (resp *types.InitFaceVerifyResp, err error) {
|
||||
order, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, req.OrderNo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询订单失败: %v", err)
|
||||
}
|
||||
|
||||
if order.Status != "paid" {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "订单未支付")
|
||||
}
|
||||
|
||||
authorization, err := l.svcCtx.AuthorizationModel.FindOneByOrderId(l.ctx, order.Id)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询授权信息失败: %v", err)
|
||||
}
|
||||
|
||||
if authorization.Status != "pending" {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "授权信息状态不正确")
|
||||
}
|
||||
key, decodeErr := hex.DecodeString(l.svcCtx.Config.Encrypt.SecretKey)
|
||||
if decodeErr != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询授权信息失败: %v", decodeErr)
|
||||
}
|
||||
if authorization.GrantType == "face" {
|
||||
authorizationFaceBuilder := l.svcCtx.AuthorizationFaceModel.SelectBuilder().
|
||||
Where("authorization_id = ? AND status = ? AND certify_id != '' AND certify_url != ''",
|
||||
authorization.Id, model.AuthorizationStatusPending).
|
||||
OrderBy("create_time DESC").
|
||||
Limit(1)
|
||||
existingFaces, err := l.svcCtx.AuthorizationFaceModel.FindAll(l.ctx, authorizationFaceBuilder, "")
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询人脸认证记录失败: %v", err)
|
||||
}
|
||||
if len(existingFaces) > 0 {
|
||||
// 如果存在记录,直接返回最新的认证信息
|
||||
return &types.InitFaceVerifyResp{
|
||||
CertifyId: existingFaces[0].CertifyId,
|
||||
CertifyUrl: existingFaces[0].CertifyUrl,
|
||||
}, nil
|
||||
}
|
||||
|
||||
}
|
||||
outerOrderNo := genOuterOrderNo()
|
||||
name, err := crypto.AesDecrypt(authorization.TargetName, key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "解密姓名失败: %v", err)
|
||||
}
|
||||
idCard, err := crypto.AesDecrypt(authorization.TargetIdcard, key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "解密身份证号失败: %v", err)
|
||||
}
|
||||
initFaceVerifyResp, err := l.svcCtx.CloudAuthService.InitFaceVerify(cloudauth.InitFaceVerifyParam{
|
||||
OuterOrderNo: outerOrderNo,
|
||||
CertName: string(name),
|
||||
CertNo: string(idCard),
|
||||
MetaInfo: req.MetaInfo,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "初始化人脸认证失败: %v", err)
|
||||
}
|
||||
err = l.svcCtx.AuthorizationModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
|
||||
authorization.AuthType = sql.NullInt64{
|
||||
Int64: req.AuthType,
|
||||
Valid: true,
|
||||
}
|
||||
_, err = l.svcCtx.AuthorizationModel.Update(l.ctx, session, authorization)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
authorizationFace := &model.AuthorizationFace{
|
||||
AuthorizationId: authorization.Id,
|
||||
CertifyId: initFaceVerifyResp.CertifyId,
|
||||
CertifyUrl: initFaceVerifyResp.CertifyUrl,
|
||||
Status: model.AuthorizationStatusPending,
|
||||
CertifyUrlExpireAt: time.Now().Add(time.Minute * 30),
|
||||
OuterOrderNo: outerOrderNo,
|
||||
}
|
||||
_, err = l.svcCtx.AuthorizationFaceModel.Insert(l.ctx, session, authorizationFace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "更新授权信息失败: %v", err)
|
||||
}
|
||||
return &types.InitFaceVerifyResp{
|
||||
CertifyId: initFaceVerifyResp.CertifyId,
|
||||
CertifyUrl: initFaceVerifyResp.CertifyUrl,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"qnc-server/app/user/cmd/api/internal/svc"
|
||||
"qnc-server/app/user/cmd/api/internal/types"
|
||||
|
||||
"github.com/zeromicro/go-zero/core/logx"
|
||||
)
|
||||
|
||||
type RejectAuthorizationLogic struct {
|
||||
logx.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
func NewRejectAuthorizationLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RejectAuthorizationLogic {
|
||||
return &RejectAuthorizationLogic{
|
||||
Logger: logx.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *RejectAuthorizationLogic) RejectAuthorization(req *types.RejectAuthorizationReq) (resp *types.RejectAuthorizationResp, err error) {
|
||||
// todo: add your logic here and delete this line
|
||||
|
||||
return
|
||||
}
|
||||
Reference in New Issue
Block a user