From e0a37f4a11dc9e681deb7ee25bed5d3c2efcab48 Mon Sep 17 00:00:00 2001 From: huang Date: Fri, 17 Apr 2026 14:49:11 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20verify-asset=20=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=8D=A1=E7=BB=91=E5=AE=9A=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 --- internal/service/client_auth/service.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/internal/service/client_auth/service.go b/internal/service/client_auth/service.go index 8f401d1..71b8100 100644 --- a/internal/service/client_auth/service.go +++ b/internal/service/client_auth/service.go @@ -106,6 +106,16 @@ func (s *Service) VerifyAsset(ctx context.Context, req *dto.VerifyAssetRequest, return nil, err } + // 如果是卡类型,检查是否绑定了设备 + // TODO: resolveAsset 可返回完整卡对象以避免二次查询,后续优化 + if assetType == assetTypeIotCard { + if bound, checkErr := s.checkCardBoundToDevice(ctx, assetID); checkErr != nil { + return nil, checkErr + } else if bound { + return nil, errors.New(errors.CodeForbidden, "该卡绑定了设备,请使用设备的虚拟号/设备号/IEMI/SN登录") + } + } + assetToken, err := s.signAssetToken(assetType, assetID) if err != nil { s.logger.Error("签发资产令牌失败", zap.Error(err)) @@ -596,6 +606,20 @@ func (s *Service) findOrCreateCustomer( return newCustomer.ID, true, nil } +// checkCardBoundToDevice 检查卡是否绑定了设备 +// 返回 true 表示已绑定设备,false 表示未绑定 +func (s *Service) checkCardBoundToDevice(ctx context.Context, cardID uint) (bool, error) { + var card model.IotCard + if err := s.db.WithContext(ctx).Select("is_standalone", "device_virtual_no").First(&card, cardID).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return false, errors.New(errors.CodeAssetNotFound) + } + return false, errors.Wrap(errors.CodeInternalError, err, "查询卡绑定状态失败") + } + // is_standalone = false 表示已绑定设备,或者 device_virtual_no 不为空也表示已绑定 + return !card.IsStandalone || card.DeviceVirtualNo != "", nil +} + // bindAsset 绑定客户与资产关系 func (s *Service) bindAsset(ctx context.Context, tx *gorm.DB, customerID uint, assetType string, assetID uint) error { assetKey, err := s.resolveAssetBindingKey(ctx, tx, assetType, assetID)