refactor(auth): replace dashboard sessions with stateless tokens and session control (#6329)
* refactor(auth): replace dashboard sessions with stateless tokens * feat(auth): harden session issuance and distributed enforcement * fix(proxy): preserve trusted proxy compatibility defaults * refactor: address dashboard auth review feedback * refactor: remove classic frontend and flatten web app
This commit is contained in:
+28
-13
@@ -431,7 +431,7 @@ func getUserGroupByIdTx(tx *gorm.DB, userId int) (string, error) {
|
||||
tx = DB
|
||||
}
|
||||
var group string
|
||||
if err := tx.Model(&User{}).Where("id = ?", userId).Select(commonGroupCol).Find(&group).Error; err != nil {
|
||||
if err := lockForUpdate(tx).Model(&User{}).Where("id = ?", userId).Select(commonGroupCol).Find(&group).Error; err != nil {
|
||||
return "", err
|
||||
}
|
||||
return group, nil
|
||||
@@ -557,6 +557,12 @@ func CreateUserSubscriptionFromPlanTx(tx *gorm.DB, userId int, plan *Subscriptio
|
||||
return sub, nil
|
||||
}
|
||||
|
||||
func refreshSubscriptionUserGroupCache(userId int, operation string) {
|
||||
if err := RefreshUserGroupCache(userId); err != nil {
|
||||
common.SysError(fmt.Sprintf("failed to refresh user group cache after %s for user %d: %v", operation, userId, err))
|
||||
}
|
||||
}
|
||||
|
||||
// Complete a subscription order (idempotent). Creates a UserSubscription snapshot from the plan.
|
||||
// expectedPaymentProvider guards against cross-gateway callback attacks (empty skips the check).
|
||||
// actualPaymentMethod updates the order's PaymentMethod to reflect the real payment type used (empty skips update).
|
||||
@@ -594,11 +600,13 @@ func CompleteSubscriptionOrder(tradeNo string, providerPayload string, expectedP
|
||||
if !plan.Enabled {
|
||||
// still allow completion for already purchased orders
|
||||
}
|
||||
upgradeGroup = strings.TrimSpace(plan.UpgradeGroup)
|
||||
_, err = CreateUserSubscriptionFromPlanTx(tx, order.UserId, plan, "order")
|
||||
subscription, err := CreateUserSubscriptionFromPlanTx(tx, order.UserId, plan, "order")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if subscription.PrevUserGroup != "" {
|
||||
upgradeGroup = strings.TrimSpace(subscription.UpgradeGroup)
|
||||
}
|
||||
if err := upsertSubscriptionTopUpTx(tx, &order); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -623,7 +631,7 @@ func CompleteSubscriptionOrder(tradeNo string, providerPayload string, expectedP
|
||||
return err
|
||||
}
|
||||
if upgradeGroup != "" && logUserId > 0 {
|
||||
_ = UpdateUserGroupCache(logUserId, upgradeGroup)
|
||||
refreshSubscriptionUserGroupCache(logUserId, "subscription payment completion")
|
||||
}
|
||||
if logUserId > 0 {
|
||||
msg := fmt.Sprintf("订阅购买成功,套餐: %s,支付金额: %.2f,支付方式: %s", logPlanTitle, logMoney, logPaymentMethod)
|
||||
@@ -702,15 +710,19 @@ func AdminBindSubscription(userId int, planId int, sourceNote string) (string, e
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
groupChanged := false
|
||||
err = DB.Transaction(func(tx *gorm.DB) error {
|
||||
_, err := CreateUserSubscriptionFromPlanTx(tx, userId, plan, "admin")
|
||||
subscription, err := CreateUserSubscriptionFromPlanTx(tx, userId, plan, "admin")
|
||||
if err == nil {
|
||||
groupChanged = subscription.PrevUserGroup != ""
|
||||
}
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if strings.TrimSpace(plan.UpgradeGroup) != "" {
|
||||
_ = UpdateUserGroupCache(userId, plan.UpgradeGroup)
|
||||
if groupChanged {
|
||||
refreshSubscriptionUserGroupCache(userId, "admin subscription creation")
|
||||
return fmt.Sprintf("用户分组将升级到 %s", plan.UpgradeGroup), nil
|
||||
}
|
||||
return "", nil
|
||||
@@ -774,7 +786,8 @@ func PurchaseSubscriptionWithBalance(userId int, planId int) error {
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := CreateUserSubscriptionFromPlanTx(tx, userId, plan, PaymentMethodBalance); err != nil {
|
||||
subscription, err := CreateUserSubscriptionFromPlanTx(tx, userId, plan, PaymentMethodBalance)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -799,7 +812,9 @@ func PurchaseSubscriptionWithBalance(userId int, planId int) error {
|
||||
logPlanTitle = plan.Title
|
||||
logMoney = plan.PriceAmount
|
||||
chargedQuota = requiredQuota
|
||||
upgradeGroup = strings.TrimSpace(plan.UpgradeGroup)
|
||||
if subscription.PrevUserGroup != "" {
|
||||
upgradeGroup = strings.TrimSpace(subscription.UpgradeGroup)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
@@ -812,7 +827,7 @@ func PurchaseSubscriptionWithBalance(userId int, planId int) error {
|
||||
}
|
||||
}
|
||||
if upgradeGroup != "" {
|
||||
_ = UpdateUserGroupCache(userId, upgradeGroup)
|
||||
refreshSubscriptionUserGroupCache(userId, "subscription balance purchase")
|
||||
}
|
||||
msg := fmt.Sprintf("使用余额购买订阅成功,套餐: %s,支付金额: %.2f,扣除额度: %d", logPlanTitle, logMoney, chargedQuota)
|
||||
RecordLog(userId, LogTypeTopup, msg)
|
||||
@@ -935,7 +950,7 @@ func AdminInvalidateUserSubscription(userSubscriptionId int) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
if cacheGroup != "" && userId > 0 {
|
||||
_ = UpdateUserGroupCache(userId, cacheGroup)
|
||||
refreshSubscriptionUserGroupCache(userId, "admin subscription update")
|
||||
}
|
||||
if downgradeGroup != "" {
|
||||
return fmt.Sprintf("用户分组将回退到 %s", downgradeGroup), nil
|
||||
@@ -976,7 +991,7 @@ func AdminDeleteUserSubscription(userSubscriptionId int) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
if cacheGroup != "" && userId > 0 {
|
||||
_ = UpdateUserGroupCache(userId, cacheGroup)
|
||||
refreshSubscriptionUserGroupCache(userId, "admin subscription deletion")
|
||||
}
|
||||
if downgradeGroup != "" {
|
||||
return fmt.Sprintf("用户分组将回退到 %s", downgradeGroup), nil
|
||||
@@ -1203,7 +1218,7 @@ func ExpireDueSubscriptions(limit int) (int, error) {
|
||||
return expiredCount, err
|
||||
}
|
||||
if cacheGroup != "" {
|
||||
_ = UpdateUserGroupCache(userId, cacheGroup)
|
||||
refreshSubscriptionUserGroupCache(userId, "subscription expiration")
|
||||
}
|
||||
}
|
||||
return expiredCount, nil
|
||||
|
||||
Reference in New Issue
Block a user