You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

88 lines
2.7 KiB

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)。
*
* <p>字段含义(S02 固定):</p>
* <ul>
* <li>{@code tokenHash} —— **Refresh Token 原文的 HMAC-SHA256 摘要**,绝不保存原文;</li>
* <li>{@code tokenType} —— 新记录固定 {@code REFRESH};</li>
* <li>{@code expiredAt} —— Refresh Token 到期时间;</li>
* <li>{@code revoked} —— 兼容既有布尔语义,与 {@code revokedAt} 同步维护;</li>
* <li>{@code refreshTokenHash} —— 旧字段保留,S02 新逻辑不依赖。</li>
* </ul>
*
* <p>旧数据({@code sessionId IS NULL})永远不被新鉴权逻辑视为活动会话。</p>
*/
@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;
}