add gigawear auth repository

This commit is contained in:
2026-09-14 18:30:53 +03:00
parent e77046018d
commit f41d7aec33
23 changed files with 254 additions and 41 deletions
@@ -4,7 +4,6 @@ import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import org.koin.core.annotation.Single
import ru.shadowsparky.backend.domain.JwtInfo
import ru.shadowsparky.backend.domain.LOGIN_NAME
import ru.shadowsparky.backend.domain.USER_ID_ARG
import java.util.Date
import java.util.concurrent.TimeUnit
@@ -15,15 +14,11 @@ class JwtPreparer(
private val envFetcher: EnvFetcher
) {
private val tokenTimeInMinutes = envFetcher.get("JWT_DURATION", "30").toLong()
fun prepare(
login: String,
userId: Long
): String {
fun prepare(userId: Long): String {
val exp = Date(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(tokenTimeInMinutes))
val token = JWT.create()
.withAudience(jwtInfo.audience)
.withIssuer(jwtInfo.issuer)
.withClaim(LOGIN_NAME, login)
.withClaim(USER_ID_ARG, userId)
.withSubject(userId.toString())
.withExpiresAt(exp)
@@ -0,0 +1,18 @@
package ru.shadowsparky.backend.data
import java.security.MessageDigest
import java.security.SecureRandom
import kotlin.io.encoding.Base64
fun generateRefreshToken(): String {
val refresh = ByteArray(32)
SecureRandom().nextBytes(refresh)
return refresh.toHexString()
}
fun String.toTokenHash(salt: String): String {
val md = MessageDigest.getInstance("SHA-256")
md.update(salt.toByteArray())
val result = md.digest(this.toByteArray())
return Base64.encode(result)
}
@@ -6,8 +6,8 @@ import com.auth0.jwt.algorithms.Algorithm
import com.auth0.jwt.interfaces.DecodedJWT
import org.koin.core.annotation.Factory
import ru.shadowsparky.backend.domain.JwtInfo
import ru.shadowsparky.backend.domain.LOGIN_NAME
import ru.shadowsparky.backend.domain.LoginVerifier
import ru.shadowsparky.backend.domain.USER_ID_ARG
@Factory
class TokenVerifier(
@@ -22,7 +22,7 @@ class TokenVerifier(
suspend fun verify(token: String): DecodedJWT {
val jwt = verifier.verify(token)
loginVerifier.verify(jwt.getClaim(LOGIN_NAME).asString())
loginVerifier.verify(jwt.getClaim(USER_ID_ARG).asLong())
return jwt
}
}
@@ -1,10 +1,9 @@
package ru.shadowsparky.backend.domain
interface LoginVerifier {
suspend fun verify(login: String)
suspend fun verify(userId: Long)
}
const val LOGIN_NAME = "login"
const val USER_ID_ARG = "user_id"
const val INVALID_TOKEN_MSG = "Для выполнения этого действия требуется авторизация."
@@ -16,7 +16,6 @@ import ru.shadowsparky.backend.data.TokenVerifier
import ru.shadowsparky.backend.domain.ExceptionInfo
import ru.shadowsparky.backend.domain.INVALID_TOKEN_MSG
import ru.shadowsparky.backend.domain.JwtInfo
import ru.shadowsparky.backend.domain.LOGIN_NAME
import ru.shadowsparky.backend.domain.LoginVerifier
import ru.shadowsparky.backend.domain.USER_ID_ARG
import ru.shadowsparky.backend.domain.VerifyTokenException
@@ -44,10 +43,10 @@ fun Application.configureJwt(
realm = jwtInfo.realm
verifier(tokenVerifier.verifier)
validate { credential ->
val login = credential.payload.getClaim(LOGIN_NAME).asString()
val userId = credential.payload.getClaim(USER_ID_ARG).asLong()
try {
if (login != null) {
loginVerifier.verify(login)
if (userId != null) {
loginVerifier.verify(userId)
if (credential.payload.expiresAt == null) {
throw VerifyTokenException("Static tokens not supported!")
}