修复鉴权:401拦截器加refresh重试 + admin refresh接口 + 路由守卫完善
根因:access_token每2小时过期,前端收到401直接清token跳登录,没有用refresh_token续期 后端修复: - adminauth模块新增 POST /admin/auth/refresh 接口 - Service 注入 JWTManager,支持 admin refresh token 换新 token pair - Refresh 方法验证 subjectType=admin + tokenType=refresh 前端修复: - 401 拦截器核心改造:收到401先调 refresh 接口续期 - 加 isRefreshing 锁 + pendingRequests 队列防止并发刷新 - refresh 用原生 axios.post 避免拦截器递归 - 成功则更新 localStorage + 重试原请求,失败才清 token 跳登录 - 排除 /auth/refresh 自身避免死循环 - 支持 /admin/ 请求独立 token 管理 - auth.ts/adminAuth.ts 新增手动 refreshUserToken/refreshAdminSession - 路由守卫给所有需登录路由添加 meta.requiresAuth - 守卫同时支持 PC 端 /login 和移动端 /m/login
This commit is contained in:
@@ -158,26 +158,41 @@ func (r *Repository) SubmitReview(ownerID uint64, listingID uint64, reviewRequir
|
||||
return dto, err
|
||||
}
|
||||
|
||||
func (r *Repository) ListPendingReview() ([]ListingDTO, error) {
|
||||
func (r *Repository) ListPendingReview(page, pageSize int) (*PaginatedResult, error) {
|
||||
conditions := r.db.Model(&model.RentalListing{}).Where("review_status = ?", "pending")
|
||||
var total int64
|
||||
if err := conditions.Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
offset := (page - 1) * pageSize
|
||||
var rows []listingRow
|
||||
err := r.baseQuery().
|
||||
err := r.listQuery().
|
||||
Where("l.review_status = ?", "pending").
|
||||
Order("l.updated_at ASC, l.id ASC").
|
||||
Limit(200).
|
||||
Offset(offset).Limit(pageSize).
|
||||
Scan(&rows).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rowsToDTO(rows), nil
|
||||
return &PaginatedResult{Items: rowsToDTO(rows), Total: total, Page: page, PageSize: pageSize}, nil
|
||||
}
|
||||
|
||||
func (r *Repository) ListAdmin(query AdminListQuery) ([]ListingDTO, error) {
|
||||
limit := query.Limit
|
||||
if limit <= 0 || limit > 500 {
|
||||
limit = 200
|
||||
func (r *Repository) ListAdmin(query AdminListQuery) (*PaginatedResult, error) {
|
||||
conditions := r.db.Model(&model.RentalListing{})
|
||||
if query.OwnerID > 0 {
|
||||
conditions = conditions.Where("owner_id = ?", query.OwnerID)
|
||||
}
|
||||
|
||||
db := r.baseQuery()
|
||||
if query.Status != "" {
|
||||
conditions = conditions.Where("status = ?", query.Status)
|
||||
}
|
||||
if query.ReviewStatus != "" {
|
||||
conditions = conditions.Where("review_status = ?", query.ReviewStatus)
|
||||
}
|
||||
var total int64
|
||||
if err := conditions.Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
db := r.listQuery()
|
||||
if query.OwnerID > 0 {
|
||||
db = db.Where("l.owner_id = ?", query.OwnerID)
|
||||
}
|
||||
@@ -187,13 +202,13 @@ func (r *Repository) ListAdmin(query AdminListQuery) ([]ListingDTO, error) {
|
||||
if query.ReviewStatus != "" {
|
||||
db = db.Where("l.review_status = ?", query.ReviewStatus)
|
||||
}
|
||||
|
||||
offset := (query.Page - 1) * query.PageSize
|
||||
var rows []listingRow
|
||||
err := db.Order("l.id DESC").Limit(limit).Scan(&rows).Error
|
||||
err := db.Order("l.id DESC").Offset(offset).Limit(query.PageSize).Scan(&rows).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rowsToDTO(rows), nil
|
||||
return &PaginatedResult{Items: rowsToDTO(rows), Total: total, Page: query.Page, PageSize: query.PageSize}, nil
|
||||
}
|
||||
|
||||
func (r *Repository) FindAdmin(listingID uint64) (*ListingDTO, error) {
|
||||
@@ -358,29 +373,43 @@ func (r *Repository) Offline(ownerID uint64, listingID uint64) error {
|
||||
})
|
||||
}
|
||||
|
||||
func (r *Repository) ListPublic() ([]ListingDTO, error) {
|
||||
func (r *Repository) ListPublic(page, pageSize int) (*PaginatedResult, error) {
|
||||
conditions := r.db.Model(&model.RentalListing{}).Where("status = ? AND review_status = ?", "published", "approved")
|
||||
var total int64
|
||||
if err := conditions.Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
offset := (page - 1) * pageSize
|
||||
var rows []listingRow
|
||||
err := r.baseQuery().
|
||||
err := r.listQuery().
|
||||
Where("l.status = ? AND l.review_status = ?", "published", "approved").
|
||||
Order("l.published_at DESC, l.id DESC").
|
||||
Limit(100).
|
||||
Offset(offset).Limit(pageSize).
|
||||
Scan(&rows).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return publicListings(rowsToDTO(rows)), nil
|
||||
items := publicListings(rowsToDTO(rows))
|
||||
return &PaginatedResult{Items: items, Total: total, Page: page, PageSize: pageSize}, nil
|
||||
}
|
||||
|
||||
func (r *Repository) ListMine(ownerID uint64) ([]ListingDTO, error) {
|
||||
func (r *Repository) ListMine(ownerID uint64, page, pageSize int) (*PaginatedResult, error) {
|
||||
conditions := r.db.Model(&model.RentalListing{}).Where("owner_id = ?", ownerID)
|
||||
var total int64
|
||||
if err := conditions.Count(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
offset := (page - 1) * pageSize
|
||||
var rows []listingRow
|
||||
err := r.baseQuery().
|
||||
err := r.listQuery().
|
||||
Where("l.owner_id = ?", ownerID).
|
||||
Order("l.id DESC").
|
||||
Offset(offset).Limit(pageSize).
|
||||
Scan(&rows).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rowsToDTO(rows), nil
|
||||
return &PaginatedResult{Items: rowsToDTO(rows), Total: total, Page: page, PageSize: pageSize}, nil
|
||||
}
|
||||
|
||||
func (r *Repository) FindPublic(id uint64) (*ListingDTO, error) {
|
||||
@@ -449,6 +478,17 @@ func (r *Repository) baseQuery() *gorm.DB {
|
||||
Joins("LEFT JOIN users AS u ON u.id = l.owner_id")
|
||||
}
|
||||
|
||||
// listQuery returns a SELECT-optimized query for list endpoints (excludes heavy fields like description, screenshot_urls, asset_summary).
|
||||
func (r *Repository) listQuery() *gorm.DB {
|
||||
return r.db.Table("rental_listings AS l").
|
||||
Select(`l.id, l.account_id, l.owner_id, l.price_hourly, l.price_daily, l.price_weekly, l.deposit_amount,
|
||||
l.status, l.review_status, l.review_reason, l.published_at, l.created_at, l.updated_at,
|
||||
a.title, a.game_name, a.server_region, a.login_platform, a.rank_level, a.haf_coin_amount,
|
||||
COALESCE(u.phone, '') AS owner_phone, COALESCE(u.nickname, '') AS owner_nickname`).
|
||||
Joins("JOIN game_accounts AS a ON a.id = l.account_id").
|
||||
Joins("LEFT JOIN users AS u ON u.id = l.owner_id")
|
||||
}
|
||||
|
||||
func (r *Repository) findForReviewUpdate(tx *gorm.DB, listingID uint64) (*model.RentalListing, *model.GameAccount, error) {
|
||||
var listing model.RentalListing
|
||||
if err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).First(&listing, listingID).Error; err != nil {
|
||||
|
||||
Reference in New Issue
Block a user