Return JSON error bodies for auth and exceptions
All checks were successful
build-and-deploy / build-deploy (push) Successful in 27s

This commit is contained in:
androidlover5842
2026-01-27 02:52:08 +05:30
parent 7f7e164acf
commit 188738e28b
2 changed files with 99 additions and 4 deletions

View File

@@ -0,0 +1,71 @@
package com.android.trisolarisserver.config
import jakarta.servlet.http.HttpServletRequest
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.security.access.AccessDeniedException
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.RestControllerAdvice
import org.springframework.web.server.ResponseStatusException
import java.time.OffsetDateTime
@RestControllerAdvice
class ApiExceptionHandler {
@ExceptionHandler(ResponseStatusException::class)
fun handleResponseStatus(
ex: ResponseStatusException,
request: HttpServletRequest
): ResponseEntity<ApiError> {
val status = ex.statusCode as HttpStatus
return ResponseEntity.status(status).body(
ApiError(
timestamp = OffsetDateTime.now().toString(),
status = status.value(),
error = status.reasonPhrase,
message = ex.reason ?: "Request failed",
path = request.requestURI
)
)
}
@ExceptionHandler(AccessDeniedException::class)
fun handleAccessDenied(
ex: AccessDeniedException,
request: HttpServletRequest
): ResponseEntity<ApiError> {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(
ApiError(
timestamp = OffsetDateTime.now().toString(),
status = HttpStatus.FORBIDDEN.value(),
error = HttpStatus.FORBIDDEN.reasonPhrase,
message = ex.message ?: "Forbidden",
path = request.requestURI
)
)
}
@ExceptionHandler(Exception::class)
fun handleGeneric(
ex: Exception,
request: HttpServletRequest
): ResponseEntity<ApiError> {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(
ApiError(
timestamp = OffsetDateTime.now().toString(),
status = HttpStatus.INTERNAL_SERVER_ERROR.value(),
error = HttpStatus.INTERNAL_SERVER_ERROR.reasonPhrase,
message = ex.message ?: "Internal server error",
path = request.requestURI
)
)
}
}
data class ApiError(
val timestamp: String,
val status: Int,
val error: String,
val message: String,
val path: String
)

View File

@@ -9,11 +9,15 @@ import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
import org.springframework.security.web.authentication.HttpStatusEntryPoint
import org.springframework.http.HttpStatus
import com.fasterxml.jackson.databind.ObjectMapper
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
@Configuration(proxyBeanMethods = false)
@EnableMethodSecurity
class SecurityConfig(
private val firebaseAuthFilter: FirebaseAuthFilter
private val firebaseAuthFilter: FirebaseAuthFilter,
private val objectMapper: ObjectMapper
) {
@Bean
fun filterChain(http: HttpSecurity): SecurityFilterChain {
@@ -25,9 +29,11 @@ class SecurityConfig(
it.anyRequest().authenticated()
}
.exceptionHandling {
it.authenticationEntryPoint(HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
it.accessDeniedHandler { _, response, _ ->
response.sendError(HttpStatus.FORBIDDEN.value(), "Forbidden")
it.authenticationEntryPoint { request, response, _ ->
writeError(response, request, HttpStatus.UNAUTHORIZED, "Unauthorized")
}
it.accessDeniedHandler { request, response, _ ->
writeError(response, request, HttpStatus.FORBIDDEN, "Forbidden")
}
}
.httpBasic { it.disable() }
@@ -35,4 +41,22 @@ class SecurityConfig(
.addFilterBefore(firebaseAuthFilter, UsernamePasswordAuthenticationFilter::class.java)
return http.build()
}
private fun writeError(
response: HttpServletResponse,
request: HttpServletRequest,
status: HttpStatus,
message: String
) {
if (response.isCommitted) return
response.status = status.value()
response.contentType = "application/json"
val body = mapOf(
"status" to status.value(),
"error" to status.reasonPhrase,
"message" to message,
"path" to request.requestURI
)
response.writer.use { it.write(objectMapper.writeValueAsString(body)) }
}
}