This commit is contained in:
Vladimir Voronin
2025-01-07 12:35:17 +03:00
commit afd8e9f6d7
72 changed files with 4606 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
package space.luminic.budgerapp.configs
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
import java.util.concurrent.Executor
//
//@Configuration
//class AsyncConfig {
// @Bean(name = ["taskExecutor"])
// fun taskExecutor(): Executor {
// val executor = ThreadPoolTaskExecutor()
// executor.corePoolSize = 5
// executor.maxPoolSize = 10
// executor.setQueueCapacity(25)
// executor.setThreadNamePrefix("Async-")
// executor.initialize()
// return executor
// }
//}

View File

@@ -0,0 +1,60 @@
package space.luminic.budgerapp.configs
import org.slf4j.LoggerFactory
import org.springframework.http.HttpHeaders
import org.springframework.http.HttpMethod
import org.springframework.http.HttpStatus
import org.springframework.security.authentication.BadCredentialsException
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.AuthenticationException
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.security.core.context.ReactiveSecurityContextHolder
import org.springframework.security.core.context.SecurityContext
import org.springframework.security.core.context.SecurityContextImpl
import org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter
import org.springframework.stereotype.Component
import org.springframework.web.server.ServerWebExchange
import org.springframework.web.server.WebFilterChain
import reactor.core.publisher.Mono
import space.luminic.budgerapp.services.AuthService
@Component
class BearerTokenFilter(private val authService: AuthService) : SecurityContextServerWebExchangeWebFilter() {
private val logger = LoggerFactory.getLogger(BearerTokenFilter::class.java)
override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
val token = exchange.request.headers.getFirst(HttpHeaders.AUTHORIZATION)?.removePrefix("Bearer ")
if (exchange.request.path.value() == "/api/auth/login"){
return chain.filter(exchange)
}
return if (token != null) {
authService.isTokenValid(token)
.flatMap { userDetails ->
val authorities = userDetails.roles.map { SimpleGrantedAuthority(it) }
val securityContext = SecurityContextImpl(
UsernamePasswordAuthenticationToken(
userDetails.username, null, authorities
)
)
chain.filter(exchange)
.contextWrite(ReactiveSecurityContextHolder.withSecurityContext(Mono.just(securityContext)))
}
.onErrorMap(AuthException::class.java) { ex ->
BadCredentialsException(ex.message ?: "Unauthorized")
}
} else {
Mono.error(AuthException("Authorization token is missing"))
}
}
}
open class AuthException(msg: String) : RuntimeException(msg)

View File

@@ -0,0 +1,18 @@
package space.luminic.budgerapp.configs
import org.springframework.context.annotation.Configuration
import org.springframework.web.reactive.config.CorsRegistry
import org.springframework.web.reactive.config.WebFluxConfigurer
@Configuration
class CorsConfig : WebFluxConfigurer {
override fun addCorsMappings(registry: CorsRegistry) {
registry.addMapping("/**") // Разрешить все пути
.allowedOrigins("http://localhost:5173") // Разрешить домен localhost:5173
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH") // Разрешить методы
.allowedHeaders("*") // Разрешить все заголовки
.allowCredentials(true) // Разрешить передачу cookies
}
}

View File

@@ -0,0 +1,44 @@
//package space.luminic.budgerapp.configs
//import org.springframework.http.HttpHeaders
//import org.springframework.http.HttpStatus
//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
//import org.springframework.security.core.context.SecurityContextHolder
//import org.springframework.stereotype.Component
//import org.springframework.web.server.ServerWebExchange
//import org.springframework.web.server.WebFilter
//import org.springframework.web.server.WebFilterChain
//import reactor.core.publisher.Mono
//import space.luminic.budgerapp.services.AuthService
//import space.luminic.budgerapp.services.TokenService
//import space.luminic.budgerapp.utils.JWTUtil
//
//@Component
//class JWTAuthFilter(
// private val jwtUtil: JWTUtil,
// private val authService: AuthService
//) : WebFilter {
//
// override fun filter(exchange: ServerWebExchange, chain: WebFilterChain): Mono<Void> {
// val authHeader = exchange.request.headers.getFirst(HttpHeaders.AUTHORIZATION)
//
// if (authHeader != null && authHeader.startsWith("Bearer ")) {
// val token = authHeader.substring(7)
// return Mono.just(token)
// .filter { authService.isTokenValid(it) }
// .flatMap { validToken ->
// val username = jwtUtil.validateToken(validToken)
// if (username != null) {
// val auth = UsernamePasswordAuthenticationToken(username, null, emptyList())
// SecurityContextHolder.getContext().authentication = auth
// }
// chain.filter(exchange)
// }
// .onErrorResume {
// exchange.response.statusCode = HttpStatus.UNAUTHORIZED
// exchange.response.setComplete()
// }
// }
//
// return chain.filter(exchange)
// }
//}

View File

@@ -0,0 +1,33 @@
//package space.luminic.budgerapp.configs
//
//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
//import org.springframework.security.authentication.ReactiveAuthenticationManager
//import org.springframework.security.core.Authentication
//import org.springframework.security.core.userdetails.ReactiveUserDetailsService
//import org.springframework.security.crypto.password.PasswordEncoder
//import org.springframework.stereotype.Component
//import reactor.core.publisher.Mono
//import space.luminic.budgerapp.services.CustomReactiveUserDetailsService
//import space.luminic.budgerapp.services.TokenService
//import space.luminic.budgerapp.utils.JWTUtil
//
//@Component
//class JWTReactiveAuthenticationManager(
// private val passwordEncoder: PasswordEncoder,
// private val userDetailsService: CustomReactiveUserDetailsService
//) : ReactiveAuthenticationManager {
//
//
// override fun authenticate(authentication: Authentication): Mono<Authentication> {
// val username = authentication.principal as String
// val password = authentication.credentials as String
//
// return userDetailsService.findByUsername(username)
// .filter { userDetails -> password == passwordEncoder.encode(userDetails.password) } // Пример проверки пароля
// .map { userDetails ->
// UsernamePasswordAuthenticationToken(userDetails, null, userDetails.authorities)
// }
// }
//
//
//}

View File

@@ -0,0 +1,62 @@
package space.luminic.budgerapp.configs
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpMethod
import org.springframework.security.config.web.server.SecurityWebFiltersOrder
import org.springframework.security.config.web.server.ServerHttpSecurity
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.security.web.server.SecurityWebFilterChain
import space.luminic.budgerapp.controllers.CustomAuthenticationEntryPoint
import space.luminic.budgerapp.services.AuthService
@Configuration
class SecurityConfig(
private val authService: AuthService
) {
@Bean
fun securityWebFilterChain(
http: ServerHttpSecurity,
bearerTokenFilter: BearerTokenFilter,
customAuthenticationEntryPoint: CustomAuthenticationEntryPoint
): SecurityWebFilterChain {
return http
.csrf { it.disable() }
.cors { it.configurationSource(corsConfigurationSource()) }
.logout { it.disable() }
.authorizeExchange {
it.pathMatchers(HttpMethod.POST, "/auth/login").permitAll()
it.pathMatchers("/actuator/**").permitAll()
it.anyExchange().authenticated()
}
.addFilterAt(
bearerTokenFilter,
SecurityWebFiltersOrder.AUTHENTICATION
) // BearerTokenFilter только для authenticated
.build()
}
@Bean
fun passwordEncoder(): PasswordEncoder {
return BCryptPasswordEncoder()
}
@Bean
fun corsConfigurationSource(): org.springframework.web.cors.reactive.CorsConfigurationSource {
val corsConfig = org.springframework.web.cors.CorsConfiguration()
corsConfig.allowedOrigins =
listOf("https://luminic.space", "http://localhost:5173") // Ваши разрешённые источники
corsConfig.allowedMethods = listOf("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH")
corsConfig.allowedHeaders = listOf("*")
corsConfig.allowCredentials = true
val source = org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource()
source.registerCorsConfiguration("/**", corsConfig)
return source
}
}