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
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;
|
|
}
|
|
|