fix(backend): JWT config mapstructure tag 修复 + 模型从 hotel 重构为 shop

- 修复 JWTConfig 缺少 mapstructure tag 导致 access_expire_min 解析为 0,
  token 签发即过期,所有 API 请求返回 401
- 全部 config struct 补齐 mapstructure tag(secret/dsn/hmac_secret 等)
- 模型层从 hotel/HotelID 统一重命名为 shop/ShopID
- 删除旧 migrations(001-004),新增 001_init 综合迁移文件
- 更新 schema.sql、testutil、handler/service/model 相关引用

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
wangjia
2026-04-07 22:20:12 +08:00
parent 37112d6599
commit 31ea370cea
50 changed files with 2675 additions and 951 deletions
+11 -11
View File
@@ -16,10 +16,10 @@ import (
)
var (
ErrLicenseNotFound = errors.New("license not found")
ErrLicenseInactive = errors.New("license is inactive")
ErrLicenseExpired = errors.New("license has expired")
ErrDeviceMismatch = errors.New("license is bound to another device")
ErrLicenseNotFound = errors.New("license not found")
ErrLicenseInactive = errors.New("license is inactive")
ErrLicenseExpired = errors.New("license has expired")
ErrDeviceMismatch = errors.New("license is bound to another device")
)
type LicenseService struct {
@@ -31,9 +31,9 @@ func NewLicenseService(db *gorm.DB) *LicenseService {
}
// GenerateKey 生成许可证激活码
// 格式:HMAC-SHA256(hotelID+deviceID+expiry, secret) → base32, 每5字符加'-'
func GenerateKey(hotelID uint64, licenseType string, expiresAt *time.Time) string {
payload := fmt.Sprintf("%d:%s", hotelID, licenseType)
// 格式:HMAC-SHA256(shopID+licenseType+expiry, secret) → base32, 每5字符加'-'
func GenerateKey(shopID uint64, licenseType string, expiresAt *time.Time) string {
payload := fmt.Sprintf("%d:%s", shopID, licenseType)
if expiresAt != nil {
payload += ":" + expiresAt.Format("20060102")
}
@@ -70,9 +70,9 @@ func (s *LicenseService) Activate(licenseKey, deviceID string) (*model.License,
}
// Verify 验证(客户端启动时调用)
func (s *LicenseService) Verify(hotelID uint64, deviceID string) (*model.License, error) {
func (s *LicenseService) Verify(shopID uint64, deviceID string) (*model.License, error) {
var lic model.License
if err := s.db.Where("hotel_id = ? AND device_id = ? AND is_active = 1", hotelID, deviceID).
if err := s.db.Where("shop_id = ? AND device_id = ? AND is_active = 1", shopID, deviceID).
First(&lic).Error; err != nil {
return nil, ErrLicenseNotFound
}
@@ -83,8 +83,8 @@ func (s *LicenseService) Verify(hotelID uint64, deviceID string) (*model.License
}
// Deactivate 解绑设备(换机时使用)
func (s *LicenseService) Deactivate(hotelID uint64, deviceID string) error {
func (s *LicenseService) Deactivate(shopID uint64, deviceID string) error {
return s.db.Model(&model.License{}).
Where("hotel_id = ? AND device_id = ?", hotelID, deviceID).
Where("shop_id = ? AND device_id = ?", shopID, deviceID).
Updates(map[string]interface{}{"device_id": "", "activated_at": nil}).Error
}