diff --git a/auth-jwt-core/src/main/kotlin/ru/touchin/auth/core/tokens/refresh/dto/RefreshToken.kt b/auth-jwt-core/src/main/kotlin/ru/touchin/auth/core/tokens/refresh/dto/RefreshToken.kt index c4988b6..b9ae985 100644 --- a/auth-jwt-core/src/main/kotlin/ru/touchin/auth/core/tokens/refresh/dto/RefreshToken.kt +++ b/auth-jwt-core/src/main/kotlin/ru/touchin/auth/core/tokens/refresh/dto/RefreshToken.kt @@ -6,5 +6,6 @@ import java.time.ZonedDateTime data class RefreshToken( val value: String, val expiresAt: ZonedDateTime, + val usedAt: ZonedDateTime?, val user: User, ) diff --git a/auth-jwt-core/src/main/kotlin/ru/touchin/auth/core/tokens/refresh/models/RefreshTokenEntity.kt b/auth-jwt-core/src/main/kotlin/ru/touchin/auth/core/tokens/refresh/models/RefreshTokenEntity.kt index 93e3c8c..5a76bef 100644 --- a/auth-jwt-core/src/main/kotlin/ru/touchin/auth/core/tokens/refresh/models/RefreshTokenEntity.kt +++ b/auth-jwt-core/src/main/kotlin/ru/touchin/auth/core/tokens/refresh/models/RefreshTokenEntity.kt @@ -25,6 +25,8 @@ class RefreshTokenEntity : AuditableUuidIdEntity() { lateinit var expiresAt: ZonedDateTime + var usedAt: ZonedDateTime? = null + @ManyToOne @JoinColumn(name = "user_id") lateinit var user: UserEntity @@ -43,7 +45,7 @@ class RefreshTokenEntity : AuditableUuidIdEntity() { lateinit var scopes: Set fun validate(): RefreshTokenEntity = this.apply { - if (expiresAt.isExpired()) { + if (expiresAt.isExpired() || usedAt != null) { throw RefreshTokenExpiredException(value) } } diff --git a/auth-jwt-core/src/main/kotlin/ru/touchin/auth/core/tokens/refresh/services/RefreshTokenCoreService.kt b/auth-jwt-core/src/main/kotlin/ru/touchin/auth/core/tokens/refresh/services/RefreshTokenCoreService.kt index b87552f..a1b15bc 100644 --- a/auth-jwt-core/src/main/kotlin/ru/touchin/auth/core/tokens/refresh/services/RefreshTokenCoreService.kt +++ b/auth-jwt-core/src/main/kotlin/ru/touchin/auth/core/tokens/refresh/services/RefreshTokenCoreService.kt @@ -7,5 +7,6 @@ interface RefreshTokenCoreService { fun get(value: String): RefreshToken fun create(token: NewRefreshToken): RefreshToken + fun setUsed(value: String): RefreshToken } diff --git a/auth-jwt-core/src/main/kotlin/ru/touchin/auth/core/tokens/refresh/services/RefreshTokenCoreServiceImpl.kt b/auth-jwt-core/src/main/kotlin/ru/touchin/auth/core/tokens/refresh/services/RefreshTokenCoreServiceImpl.kt index dbad070..b5f572a 100644 --- a/auth-jwt-core/src/main/kotlin/ru/touchin/auth/core/tokens/refresh/services/RefreshTokenCoreServiceImpl.kt +++ b/auth-jwt-core/src/main/kotlin/ru/touchin/auth/core/tokens/refresh/services/RefreshTokenCoreServiceImpl.kt @@ -52,6 +52,18 @@ class RefreshTokenCoreServiceImpl( .toDto() } + @Transactional + override fun setUsed(value: String): RefreshToken { + val refreshToken = refreshTokenRepository.findByValueOrThrow(value) + .validate() + .apply { + usedAt = ZonedDateTime.now() + } + + return refreshTokenRepository.save(refreshToken) + .toDto() + } + private fun getExpirationDate(): ZonedDateTime { return ZonedDateTime.now().plus(refreshTokenProperties.timeToLive) } @@ -69,6 +81,7 @@ class RefreshTokenCoreServiceImpl( return RefreshToken( value = value, expiresAt = expiresAt, + usedAt = usedAt, user = user.toDto(device) ) } diff --git a/auth-jwt-core/src/main/resources/auth/db/changelog/core/202107021246__alter_table__refresh_tokens.yml b/auth-jwt-core/src/main/resources/auth/db/changelog/core/202107021246__alter_table__refresh_tokens.yml new file mode 100644 index 0000000..e22ba2b --- /dev/null +++ b/auth-jwt-core/src/main/resources/auth/db/changelog/core/202107021246__alter_table__refresh_tokens.yml @@ -0,0 +1,15 @@ +databaseChangeLog: + - changeSet: + id: 202107021246__alter_table__refresh_tokens + author: touchin + preConditions: + - onFail: MARK_RAN + tableExists: + tableName: refresh_tokens + changes: + - addColumn: + tableName: refresh_tokens + columns: + - column: + name: used_at + type: TIMESTAMP WITH TIME ZONE