feat: JWT Claims 新增资产字段,登录 token 携带当前资产上下文

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-04-16 15:55:41 +08:00
parent 5d9be1d7e4
commit 520b126ecf
3 changed files with 20 additions and 6 deletions

View File

@@ -90,6 +90,8 @@ func (m *PersonalAuthMiddleware) Authenticate() fiber.Handler {
c.Locals("customer_id", claims.CustomerID) c.Locals("customer_id", claims.CustomerID)
c.Locals("customer_phone", claims.Phone) c.Locals("customer_phone", claims.Phone)
c.Locals("customer_asset_type", claims.AssetType)
c.Locals("customer_asset_id", claims.AssetID)
c.Locals("skip_owner_filter", true) c.Locals("skip_owner_filter", true)
m.logger.Debug("个人客户认证成功", m.logger.Debug("个人客户认证成功",
@@ -113,3 +115,11 @@ func GetCustomerPhone(c *fiber.Ctx) (string, bool) {
phone, ok := c.Locals("customer_phone").(string) phone, ok := c.Locals("customer_phone").(string)
return phone, ok return phone, ok
} }
// GetCurrentAsset 从 context 中获取当前登录所用的资产类型和 ID
func GetCurrentAsset(c *fiber.Ctx) (assetType string, assetID uint, ok bool) {
assetType, _ = c.Locals("customer_asset_type").(string)
assetID, _ = c.Locals("customer_asset_id").(uint)
ok = assetType != "" && assetID != 0
return
}

View File

@@ -171,7 +171,7 @@ func (s *Service) WechatLogin(ctx context.Context, req *dto.WechatLoginRequest,
return nil, err return nil, err
} }
token, needBindPhone, err := s.issueLoginToken(ctx, customerID) token, needBindPhone, err := s.issueLoginToken(ctx, customerID, assetClaims.AssetType, assetClaims.AssetID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -233,7 +233,7 @@ func (s *Service) MiniappLogin(ctx context.Context, req *dto.MiniappLoginRequest
return nil, err return nil, err
} }
token, needBindPhone, err := s.issueLoginToken(ctx, customerID) token, needBindPhone, err := s.issueLoginToken(ctx, customerID, assetClaims.AssetType, assetClaims.AssetID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -691,7 +691,7 @@ func (s *Service) markAssetAsSold(ctx context.Context, tx *gorm.DB, assetType st
return errors.New(errors.CodeInvalidParam) return errors.New(errors.CodeInvalidParam)
} }
func (s *Service) issueLoginToken(ctx context.Context, customerID uint) (string, bool, error) { func (s *Service) issueLoginToken(ctx context.Context, customerID uint, assetType string, assetID uint) (string, bool, error) {
// 查询用户已绑定的主手机号,写入 JWT供后续接口直接从 context 取用 // 查询用户已绑定的主手机号,写入 JWT供后续接口直接从 context 取用
var boundPhone string var boundPhone string
needBindPhone := false needBindPhone := false
@@ -704,7 +704,7 @@ func (s *Service) issueLoginToken(ctx context.Context, customerID uint) (string,
needBindPhone = true needBindPhone = true
} }
token, err := s.jwtManager.GeneratePersonalCustomerToken(customerID, boundPhone) token, err := s.jwtManager.GeneratePersonalCustomerToken(customerID, boundPhone, assetType, assetID)
if err != nil { if err != nil {
return "", false, errors.Wrap(errors.CodeInternalError, err, "生成登录令牌失败") return "", false, errors.Wrap(errors.CodeInternalError, err, "生成登录令牌失败")
} }
@@ -762,7 +762,7 @@ func (s *Service) DevLogin(ctx context.Context, identifier string) (string, uint
return "", 0, false, err return "", 0, false, err
} }
token, _, err := s.issueLoginToken(ctx, customerID) token, _, err := s.issueLoginToken(ctx, customerID, assetType, assetID)
if err != nil { if err != nil {
return "", 0, false, err return "", 0, false, err
} }

View File

@@ -11,6 +11,8 @@ import (
type PersonalCustomerClaims struct { type PersonalCustomerClaims struct {
CustomerID uint `json:"customer_id"` // 个人客户 ID CustomerID uint `json:"customer_id"` // 个人客户 ID
Phone string `json:"phone"` // 手机号 Phone string `json:"phone"` // 手机号
AssetType string `json:"asset_type"` // 登录所用资产类型iot_card / device
AssetID uint `json:"asset_id"` // 登录所用资产 ID
jwt.RegisteredClaims jwt.RegisteredClaims
} }
@@ -29,10 +31,12 @@ func NewJWTManager(secretKey string, tokenDuration time.Duration) *JWTManager {
} }
// GeneratePersonalCustomerToken 生成个人客户 Token // GeneratePersonalCustomerToken 生成个人客户 Token
func (m *JWTManager) GeneratePersonalCustomerToken(customerID uint, phone string) (string, error) { func (m *JWTManager) GeneratePersonalCustomerToken(customerID uint, phone string, assetType string, assetID uint) (string, error) {
claims := &PersonalCustomerClaims{ claims := &PersonalCustomerClaims{
CustomerID: customerID, CustomerID: customerID,
Phone: phone, Phone: phone,
AssetType: assetType,
AssetID: assetID,
RegisteredClaims: jwt.RegisteredClaims{ RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(m.tokenDuration)), ExpiresAt: jwt.NewNumericDate(time.Now().Add(m.tokenDuration)),
IssuedAt: jwt.NewNumericDate(time.Now()), IssuedAt: jwt.NewNumericDate(time.Now()),