package com.mydreamjob.auth; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.time.LocalDateTime; /** * 登录会话中的 Refresh Token 记录(S02)。 * *
字段含义(S02 固定):
*旧数据({@code sessionId IS NULL})永远不被新鉴权逻辑视为活动会话。
*/ @Data @Builder @NoArgsConstructor @AllArgsConstructor @Entity @Table(name = "auth_tokens") public class AuthToken { /** Token 类型:S02 起 auth_tokens 只保存 Refresh 记录。 */ public static final String TYPE_REFRESH = "REFRESH"; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "user_id", nullable = false) private Long userId; @Column(name = "token_hash", nullable = false, length = 255) private String tokenHash; @Column(name = "token_type", nullable = false, length = 20) @Builder.Default private String tokenType = TYPE_REFRESH; @Column(name = "expired_at", nullable = false) private LocalDateTime expiredAt; @Column(name = "revoked", nullable = false) @Builder.Default private Boolean revoked = false; @Column(name = "refresh_token_hash", length = 255) private String refreshTokenHash; @Column(name = "session_id", length = 36) private String sessionId; @Column(name = "token_jti", length = 36) private String tokenJti; @Column(name = "parent_token_id") private Long parentTokenId; @Column(name = "consumed_at") private LocalDateTime consumedAt; @Column(name = "revoked_at") private LocalDateTime revokedAt; @Column(name = "revocation_reason", length = 40) private String revocationReason; @Version @Column(name = "version", nullable = false) @Builder.Default private Long version = 0L; // S02:不使用 @CreatedDate —— Spring Data 审计会在持久化时用“当前时间”覆盖显式值, // 导致 created_at 与认证入口捕获的 capturedNow 不同源。生产写入路径只有 // AuthSessionService(创建会话、轮换后继)两处,均显式设置 createdAt。 @Column(name = "created_at", nullable = false, updatable = false) private LocalDateTime createdAt; }