chore: add custom error handlers
Signed-off-by: Alan Brault <alan.brault@visus.io>
This commit is contained in:
@@ -10,7 +10,7 @@ import org.springframework.web.reactive.config.WebFluxConfigurer
|
||||
@Configuration
|
||||
class ApiVersionConfig : WebFluxConfigurer {
|
||||
override fun configurePathMatching(configurer: PathMatchConfigurer) {
|
||||
configurer.addPathPrefix("/api/v1") { controller ->
|
||||
configurer.addPathPrefix("/v1") { controller ->
|
||||
val apiVersion = AnnotatedElementUtils.findMergedAnnotation(controller, ApiVersion::class.java)
|
||||
AnnotatedElementUtils.hasAnnotation(controller, RestController::class.java) && apiVersion?.version == 1
|
||||
}
|
||||
|
||||
@@ -36,6 +36,6 @@ class OpenApiConfig {
|
||||
GroupedOpenApi
|
||||
.builder()
|
||||
.group("v1")
|
||||
.pathsToMatch("/api/v1/**")
|
||||
.pathsToMatch("/v1/**")
|
||||
.build()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package io.visus.demos.kotlinapi.config
|
||||
|
||||
import io.visus.demos.kotlinapi.domain.service.UserService
|
||||
import io.visus.demos.kotlinapi.infrastructure.security.CustomAccessDeniedHandler
|
||||
import io.visus.demos.kotlinapi.infrastructure.security.CustomAuthenticationEntryPoint
|
||||
import io.visus.demos.kotlinapi.infrastructure.security.JwtAuthenticationFilter
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.context.annotation.Configuration
|
||||
@@ -24,6 +26,8 @@ import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource
|
||||
class SecurityConfig(
|
||||
private val jwtAuthenticationFilter: JwtAuthenticationFilter,
|
||||
private val userDetailsService: UserService,
|
||||
private val customAuthenticationEntryPoint: CustomAuthenticationEntryPoint,
|
||||
private val customAccessDeniedHandler: CustomAccessDeniedHandler,
|
||||
) {
|
||||
@Bean
|
||||
fun corsConfigurationSource(): CorsConfigurationSource {
|
||||
@@ -56,16 +60,20 @@ class SecurityConfig(
|
||||
.csrf { it.disable() }
|
||||
.cors { it.configurationSource(corsConfigurationSource()) }
|
||||
.securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
|
||||
.authorizeExchange { authorize ->
|
||||
.exceptionHandling { handlers ->
|
||||
handlers
|
||||
.authenticationEntryPoint(customAuthenticationEntryPoint)
|
||||
.accessDeniedHandler(customAccessDeniedHandler)
|
||||
}.authorizeExchange { authorize ->
|
||||
authorize
|
||||
.pathMatchers(
|
||||
"/swagger-ui.html",
|
||||
"/swagger-ui/**",
|
||||
"/api-docs/**",
|
||||
"/api/v1/health",
|
||||
"/api/v1/auth/login",
|
||||
"/api/v1/auth/refresh",
|
||||
"/api/v1/auth/register",
|
||||
"/v1/health",
|
||||
"/v1/auth/login",
|
||||
"/v1/auth/refresh",
|
||||
"/v1/auth/register",
|
||||
).permitAll()
|
||||
.anyExchange()
|
||||
.authenticated()
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package io.visus.demos.kotlinapi.infrastructure.security
|
||||
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.security.access.AccessDeniedException
|
||||
import org.springframework.security.web.server.authorization.ServerAccessDeniedHandler
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.web.server.ServerWebExchange
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
@Component
|
||||
class CustomAccessDeniedHandler : ServerAccessDeniedHandler {
|
||||
override fun handle(
|
||||
exchange: ServerWebExchange,
|
||||
denied: AccessDeniedException,
|
||||
): Mono<Void> =
|
||||
Mono
|
||||
.fromRunnable<Void> {
|
||||
exchange.response.statusCode = HttpStatus.FORBIDDEN
|
||||
exchange.response.headers.contentType = MediaType.APPLICATION_JSON
|
||||
}.then(
|
||||
exchange.response.writeWith(
|
||||
Mono.just(
|
||||
exchange.response.bufferFactory().wrap(
|
||||
"""{"error":"Forbidden","message":"Access denied"}""".toByteArray(),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package io.visus.demos.kotlinapi.infrastructure.security
|
||||
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.http.MediaType
|
||||
import org.springframework.security.core.AuthenticationException
|
||||
import org.springframework.security.web.server.ServerAuthenticationEntryPoint
|
||||
import org.springframework.stereotype.Component
|
||||
import org.springframework.web.server.ServerWebExchange
|
||||
import reactor.core.publisher.Mono
|
||||
|
||||
@Component
|
||||
class CustomAuthenticationEntryPoint : ServerAuthenticationEntryPoint {
|
||||
override fun commence(
|
||||
exchange: ServerWebExchange,
|
||||
ex: AuthenticationException,
|
||||
): Mono<Void> =
|
||||
Mono
|
||||
.fromRunnable<Void> {
|
||||
exchange.response.statusCode = HttpStatus.UNAUTHORIZED
|
||||
exchange.response.headers.contentType = MediaType.APPLICATION_JSON
|
||||
}.then(
|
||||
exchange.response.writeWith(
|
||||
Mono.just(
|
||||
exchange.response.bufferFactory().wrap(
|
||||
"""{"error":"Unauthorized","message":"Authentication required"}""".toByteArray(),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user