diff --git a/frontend/components/common/docs/api.tsx b/frontend/components/common/docs/api.tsx index 704ab4f4..c608d6d7 100644 --- a/frontend/components/common/docs/api.tsx +++ b/frontend/components/common/docs/api.tsx @@ -205,7 +205,6 @@ export const apiSections: PolicySection[] = [ "name": "my-dev-key", "masked_token": "at_628d...29c9", "is_admin": false, - "last_used_at": null, "created_at": "2026-06-07T21:30:00+08:00" } } @@ -219,7 +218,7 @@ export const apiSections: PolicySection[] = [

3.4 轮换令牌密钥

接口:POST /api/v1/user/access-tokens/:id/rotate

-

说明:轮换指定令牌的物理密钥值。系统将废弃原有密钥,返回新生成的明文 Token,并将 `last_used_at` 置空,令牌名称与 ID 保持一致。

+

说明:轮换指定令牌的物理密钥值。系统将废弃原有密钥,返回新生成的明文 Token,令牌名称与 ID 保持一致。

), children: [ diff --git a/frontend/components/common/settings/access-token.tsx b/frontend/components/common/settings/access-token.tsx index ccdeb1d2..24a12015 100644 --- a/frontend/components/common/settings/access-token.tsx +++ b/frontend/components/common/settings/access-token.tsx @@ -206,11 +206,15 @@ export function AccessTokenMain() {
{token.name} - {token.is_admin && ( + {token.is_admin ? ( 管理员 + ) : ( + + 用户令牌 + )}
@@ -219,7 +223,6 @@ export function AccessTokenMain() {
创建于: {formatDate(token.created_at)} - 最后使用: {formatDate(token.last_used_at)}
diff --git a/frontend/lib/services/user/user.service.ts b/frontend/lib/services/user/user.service.ts index 7cc5b4b1..5e94920f 100644 --- a/frontend/lib/services/user/user.service.ts +++ b/frontend/lib/services/user/user.service.ts @@ -6,7 +6,6 @@ export interface AccessToken { name: string; masked_token: string; is_admin: boolean; - last_used_at?: string; created_at: string; updated_at: string; } diff --git a/internal/apps/oauth/middlewares.go b/internal/apps/oauth/middlewares.go index 3ab98596..ae876fa6 100644 --- a/internal/apps/oauth/middlewares.go +++ b/internal/apps/oauth/middlewares.go @@ -6,7 +6,6 @@ package oauth import ( "net/http" - "time" "github.com/Rain-kl/Wavelet/internal/common" "github.com/Rain-kl/Wavelet/internal/db" @@ -56,9 +55,6 @@ func LoginRequired() gin.HandlerFunc { authenticated = true tokenAuth = true tokenAdmin = tokenRecord.IsAdmin - // update token last used time - now := time.Now() - db.DB(ctx).Model(&tokenRecord).Update("last_used_at", &now) } } } diff --git a/internal/apps/user/access_tokens.go b/internal/apps/user/access_tokens.go index 8a29a0cc..c6859232 100644 --- a/internal/apps/user/access_tokens.go +++ b/internal/apps/user/access_tokens.go @@ -203,7 +203,6 @@ func RotateAccessToken(c *gin.Context) { tokenRecord.TokenHash = newTokenHash tokenRecord.MaskedToken = newMaskedToken - tokenRecord.LastUsedAt = nil // 轮换后重置使用时间 if err := db.DB(ctx).Save(&tokenRecord).Error; err != nil { c.JSON(http.StatusOK, util.Err(err.Error())) diff --git a/internal/db/migrator/goose/postgres/202606110001_remove_access_token_last_used_at.sql b/internal/db/migrator/goose/postgres/202606110001_remove_access_token_last_used_at.sql new file mode 100644 index 00000000..4a0fa676 --- /dev/null +++ b/internal/db/migrator/goose/postgres/202606110001_remove_access_token_last_used_at.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +ALTER TABLE access_tokens DROP COLUMN IF EXISTS last_used_at; +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +ALTER TABLE access_tokens ADD COLUMN last_used_at TIMESTAMPTZ; +-- +goose StatementEnd diff --git a/internal/db/migrator/goose/sqlite/202606110001_remove_access_token_last_used_at.sql b/internal/db/migrator/goose/sqlite/202606110001_remove_access_token_last_used_at.sql new file mode 100644 index 00000000..1b2c38c7 --- /dev/null +++ b/internal/db/migrator/goose/sqlite/202606110001_remove_access_token_last_used_at.sql @@ -0,0 +1,9 @@ +-- +goose Up +-- +goose StatementBegin +ALTER TABLE access_tokens DROP COLUMN last_used_at; +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +ALTER TABLE access_tokens ADD COLUMN last_used_at DATETIME; +-- +goose StatementEnd diff --git a/internal/model/access_token.go b/internal/model/access_token.go index 281637d2..db548073 100644 --- a/internal/model/access_token.go +++ b/internal/model/access_token.go @@ -20,15 +20,14 @@ const ( // AccessToken 个人访问令牌实体 type AccessToken struct { - ID uint64 `json:"id" gorm:"primaryKey;autoIncrement"` - UserID uint64 `json:"user_id" gorm:"index;not null"` - Name string `json:"name" gorm:"size:128;not null"` - TokenHash string `json:"-" gorm:"size:64;uniqueIndex;not null"` - MaskedToken string `json:"masked_token" gorm:"size:64;not null"` - IsAdmin bool `json:"is_admin" gorm:"default:false"` - LastUsedAt *time.Time `json:"last_used_at"` - CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"` - UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"` + ID uint64 `json:"id" gorm:"primaryKey;autoIncrement"` + UserID uint64 `json:"user_id" gorm:"index;not null"` + Name string `json:"name" gorm:"size:128;not null"` + TokenHash string `json:"-" gorm:"size:64;uniqueIndex;not null"` + MaskedToken string `json:"masked_token" gorm:"size:64;not null"` + IsAdmin bool `json:"is_admin" gorm:"default:false"` + CreatedAt time.Time `json:"created_at" gorm:"autoCreateTime"` + UpdatedAt time.Time `json:"updated_at" gorm:"autoUpdateTime"` } // GenerateTokenString 生成加密安全的随机 Token 值