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
+15 -13
View File
@@ -30,17 +30,18 @@ type TokenPair struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
ExpiresIn int `json:"expires_in"` // 秒
ShopID uint64 `json:"shop_id"`
}
// Login 账号密码登录
func (s *AuthService) Login(hotelCode, username, password string) (*TokenPair, *model.User, error) {
var hotel model.Hotel
if err := s.db.Where("code = ?", hotelCode).First(&hotel).Error; err != nil {
func (s *AuthService) Login(shopCode, username, password string) (*TokenPair, *model.User, error) {
var shop model.Shop
if err := s.db.Where("code = ?", shopCode).First(&shop).Error; err != nil {
return nil, nil, ErrInvalidCredentials
}
var user model.User
if err := s.db.Where("hotel_id = ? AND username = ? AND deleted_at IS NULL", hotel.ID, username).
if err := s.db.Where("shop_id = ? AND username = ? AND deleted_at IS NULL", shop.ID, username).
First(&user).Error; err != nil {
return nil, nil, ErrInvalidCredentials
}
@@ -53,7 +54,7 @@ func (s *AuthService) Login(hotelCode, username, password string) (*TokenPair, *
return nil, nil, ErrInvalidCredentials
}
pair, err := s.issueTokens(user.ID, hotel.ID, user.Role)
pair, err := s.issueTokens(user.ID, shop.ID, user.Role)
if err != nil {
return nil, nil, err
}
@@ -75,18 +76,18 @@ func (s *AuthService) RefreshTokens(refreshToken string) (*TokenPair, error) {
if err != nil || !token.Valid {
return nil, errors.New("invalid refresh token")
}
return s.issueTokens(claims.UserID, claims.HotelID, claims.Role)
return s.issueTokens(claims.UserID, claims.ShopID, claims.Role)
}
func (s *AuthService) issueTokens(userID, hotelID uint64, role string) (*TokenPair, error) {
func (s *AuthService) issueTokens(userID, shopID uint64, role string) (*TokenPair, error) {
cfg := config.C.JWT
now := time.Now()
accessExp := now.Add(time.Duration(cfg.AccessExpireMin) * time.Minute)
accessClaims := middleware.Claims{
UserID: userID,
HotelID: hotelID,
Role: role,
UserID: userID,
ShopID: shopID,
Role: role,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(accessExp),
IssuedAt: jwt.NewNumericDate(now),
@@ -99,9 +100,9 @@ func (s *AuthService) issueTokens(userID, hotelID uint64, role string) (*TokenPa
refreshExp := now.Add(time.Duration(cfg.RefreshExpireH) * time.Hour)
refreshClaims := middleware.Claims{
UserID: userID,
HotelID: hotelID,
Role: role,
UserID: userID,
ShopID: shopID,
Role: role,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(refreshExp),
IssuedAt: jwt.NewNumericDate(now),
@@ -116,5 +117,6 @@ func (s *AuthService) issueTokens(userID, hotelID uint64, role string) (*TokenPa
AccessToken: accessToken,
RefreshToken: refreshToken,
ExpiresIn: cfg.AccessExpireMin * 60,
ShopID: shopID,
}, nil
}