package com.mydreamjob.auth; import java.time.Clock; import java.time.Instant; import java.time.ZoneId; import java.util.concurrent.atomic.AtomicInteger; /** * 测试专用时钟:第一次 {@link #instant()} 返回 T,之后返回一个**明显不同**的时间(T + 偏移)。 * *

用途:证明认证入口只读取一次 Clock。若某个入口读了两次,第二次取到的是 T+偏移, * 于是 JWT {@code iat}/{@code exp}、数据库 {@code created_at}/{@code expired_at} * 或审计时间就会出现两个不同的值,测试即可捕获。

* *

固定使用项目业务时区 {@code Asia/Shanghai},不依赖系统默认时区。

*/ class AdvancingClock extends Clock { static final ZoneId ZONE = ZoneId.of("Asia/Shanghai"); private final Instant first; private final Instant subsequent; private final AtomicInteger calls = new AtomicInteger(); AdvancingClock(Instant first, Instant subsequent) { this.first = first; this.subsequent = subsequent; } @Override public ZoneId getZone() { return ZONE; } @Override public Clock withZone(ZoneId zone) { return this; } @Override public Instant instant() { int call = calls.incrementAndGet(); return call == 1 ? first : subsequent; } /** 已读取次数。 */ int callCount() { return calls.get(); } /** 每个入口开始前重置,便于分别断言。 */ void reset() { calls.set(0); } }