1
resposta

lateinit var secret

Estou tendo problemas com a variavel secret se declarar ela como lateinit na classe JWTUtil.

No arquivo application.properties:

jwt.secret=2a12Dpr9yBjZksrrC34hnQEG1uDyF5HKckz3Cob4j5md1Jl3jXPF1ejzi

Na classe JWTUtil:

    @Value("\${jwt.secret}")
    private lateinit var secret: String 

Mas ao tentar fazer o login, dá exception:

2024-08-29 17:12:21.097 ERROR 16152 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception

kotlin.UninitializedPropertyAccessException: lateinit property secret has not been initialized
    at br.com.alura.forum.config.JWTUtil.generateToken(JWTUtil.kt:24) ~[classes/:na]
    at br.com.alura.forum.security.JWTLoginFilter.successfulAuthentication(JWTLoginFilter.kt:36) ~[classes/:na]

Entretanto, se eu declarar secret não sendo lateinit, funciona.

private var secret: String = "2a12Dpr9yBjZksrrC34hnQEG1uDyF5HKckz3Cob4j5md1Jl3jXPF1ejzi"

Funcionar, funciona, mas eu não queria deixar o secret em hardcoded

1 resposta

Olá, Cleyton!

No meu caso, quem estava causando este problema não era a variável secret e sim a variável que usava ela.

Aqui está o meu código atualizado com a última versão do Spring, talvez te ajude:


import io.jsonwebtoken.Jwts
import io.jsonwebtoken.security.Keys
import jakarta.annotation.PostConstruct
import org.springframework.beans.factory.annotation.Value
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.GrantedAuthority
import org.springframework.stereotype.Component
import java.nio.charset.StandardCharsets
import java.util.*
import javax.crypto.SecretKey

@Component
class JWTConfig(
    private val userService: UserService
) {

    @Value("\${jwt.secret}")
    private lateinit var secret: String

    private val expiration: Long = 60000
    private lateinit var key: SecretKey

    @PostConstruct
    fun init() {
        key = Keys.hmacShaKeyFor(secret.toByteArray(StandardCharsets.UTF_8))
    }

    fun generateToken(username: String, authorities: MutableCollection<out GrantedAuthority>): String {
        return Jwts
            .builder()
            .subject(username)
            .claim("role", authorities)
            .expiration(Date(System.currentTimeMillis() + expiration))
            .signWith(key)
            .compact()
    }

    fun isValid(jwt: String?): Boolean {
        return try {
            Jwts.parser()
                .verifyWith(key)
                .build()
                .parseSignedClaims(jwt)
            true
        } catch (e: IllegalArgumentException) {
            false
        }
    }

    fun getAuthentication(jwt: String?): UsernamePasswordAuthenticationToken {
        val username = Jwts.parser()
            .verifyWith(key)
            .build()
            .parseSignedClaims(jwt)
            .payload
            .subject
        val user = userService.loadUserByUsername(username.toString())
        return UsernamePasswordAuthenticationToken(username, null, user.authorities)
    }
}

Como eu uso a key em tudo que é canto, resolvi iniciá-la depois que o Spring pega o valor do jwt.secret. Utilizando o método init() isso é possível.

Antes, quando dava o erro para mim, eu estava pegando o valor da secret diretamente na declaração da key, como ele ainda não tinha o valor injetado na variável secret, a aplicação quebrava.

No meu caso foi isso e essa solução me atendeu. Espero que ela também te ajude.

Bom código!