Mam klasę, która odpowiada za wyciągnięcie i walidacje JWT
internal class JwtTokenFilter(private val tokenUtils: JwtTokenUtils) : OncePerRequestFilter() {
override fun doFilterInternal(
request: HttpServletRequest,
response: HttpServletResponse,
filterChain: FilterChain
) {
request.getHeader("Authorization").let {
val token = it?.replace("Bearer ", "")
if (tokenUtils.validateToken(token)) {
val id = tokenUtils.getId(token!!)
SecurityContextHolder.getContext().authentication =
UsernamePasswordAuthenticationToken(id, null, Collections.emptyList())
}
}
filterChain.doFilter(request, response)
}
}
Która jest wpięta w SpringSecurity
http.addFilterBefore(
jwtTokenFilter, UsernamePasswordAuthenticationFilter::class.java
)
Gdzie sama walidacja może się nie udać z N powodów
fun validateToken(authToken: String?, tokenType: TokenType = TokenType.ACCESS_TOKEN): Boolean {
return try {
val claims = Jwts.parser().setSigningKey(tokenSecret).parseClaimsJws(authToken)
return claims.body["type"] == tokenType.value
} catch (ex: SignatureException) {
false
} catch (ex: MalformedJwtException) {
false
} catch (ex: ExpiredJwtException) {
false
} catch (ex: UnsupportedJwtException) {
false
} catch (ex: IllegalArgumentException) {
false
}
}
Efektem jest to że w Security context ustawiam bądź nie ustawiam obiekt autentykacji. Gdy tego zabraknie, to wpadam w tę metodę, gdzie tworzę odpowiedź HTTP.
private fun configureExceptionHandling(http: HttpSecurity) {
http.exceptionHandling().authenticationEntryPoint { _, response, _ ->
response.status = HttpServletResponse.SC_UNAUTHORIZED
response.contentType = "application/json"
response.writer.write(objectMapper.writeValueAsString(ExceptionResponse(UnauthorizedException())))
}
}
Problem w tym, że nie widzę sposobu by przekazać co dokładnie się stało, czyli odpowiedzieć użytkownikowi, że albo wygasł mu token, albo podał zupełnie zły token. Metoda powyżej dostaje wyjątek z bebechów Springa, który mówi w skrócie "Full authorization is required" i tyle.
W kodzie powyżej oczywiście nie ma to jak zadziałać, aczkolwiek próbowałem
- w
JwtTokenFilter
ustawić zmienną wThreadLocal
i odczytać wconfigureExceptionHandling
- nie działa, zmienna jest nullem - nie łapać żadnego wyjątku tylko go rzucić dalej - nie działa, łapie go SpringSecurity i dostaję ten sam wyjątek co w przypadku braku autentykacji
Jak więc mogę przekazać szczegóły błędu do użytkownika?