Spring Webflux PreAuthorize 不起作用(使用 Kotlin)

问题描述 投票:0回答:1

这是我的代码:

安全配置

@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
internal class WebAuthorizationConfig(
    private val userDetailsManager: ReactiveUserDetailsManager,
    @Qualifier("customPasswordEncoder") private val passwordEncoder: PasswordEncoder
) {

    @Bean
    fun configureSecurity(
        http: ServerHttpSecurity,
        requestValidationFilter: RequestValidationFilter,
    ): SecurityWebFilterChain {
         http
            .csrf { csrf -> csrf.disable() }
            .addFilterBefore(validEndPointFilter, SecurityWebFiltersOrder.HTTP_BASIC)
            .httpBasic { httpBasic ->
                httpBasic.authenticationEntryPoint(customAuthenticationEntryPoint())
            }
            .authorizeExchange { authorize ->
                authorize
                    .anyExchange().hasAuthority("WRITE")
            }
             .authenticationManager(customAuthenticationManager())
             .securityContextRepository(customSecurityContextRepository())

        return http.build()
    }


    @Bean
    fun customAuthenticationManager(): ReactiveAuthenticationManager {
        return CustomAuthenticationManager(userDetailsManager, passwordEncoder)
    }

    @Bean
    fun customAuthenticationEntryPoint(): CustomAuthenticationEntryPoint {
        return CustomAuthenticationEntryPoint()
    }

    @Bean
    fun customSecurityContextRepository(): ServerSecurityContextRepository {
        return CustomSecurityContextRepository()
    }

}

控制器

@RestController
internal class UserController(
    @Autowired
    private val userService: UserServiceImpl,
) {

    @GetMapping("/users/{uid}")
    final suspend fun getUser(
        @PathVariable("uid") uidString: String
    ): ResponseEntity<UserDTO> {
        // validate user ID
        val uid = userService.validateUserId(uidString)
        // get from database inside this co-routine
        return withContext(Dispatchers.IO) {
            ResponseEntity.ok(userService.getUser(uid))
        }
    }
}

服务

@Service
internal class UserGetServiceDelegate(
    @Autowired
    private val userRepo: UserRepositoryImpl,
    private val userDTOEntityMapMapper: UserDTOEntityMapMapperImpl,
    private val userMapKeyRenamer: UserMapKeyRenamerImpl,
) : UserGetService {

    @PreAuthorize("denyAll()")
    final override suspend fun getUser(uid: ObjectId): UserDTO {

        //** SIGNIFICANT DATABASE STEP **//
        // attempt to get user from database
        val userEntity = userRepo.getUser(uid)
            ?: throw ErrorManager.getException("service-user-does-not-exist")

        // return retrieved user
        return userDTOEntityMapMapper.fromEntity(userEntity)
    }
}

无论我做什么,它仍然授予对服务的访问权限,并返回结果,尽管服务中有 @PreAuthorize("denyAll()")?

很多年前就有很多帖子抱怨这一点。有些人建议添加此注释@EnableReactiveMethodSecurity(已经完成)。有人建议删除final(但是kotlin,如果删除可见性修饰符,它默认是final,当我选择open或sealed时,它们会变灰,我的IDE说它们是多余的)

但他们都没有帮助。

有什么想法吗?

提前致谢

spring-boot kotlin spring-security spring-webflux
1个回答
0
投票

我采用了您的示例的一部分,并使用 Spring boot 最新的 WebFlux、Kotlin 和 Java 21 以最低的安全性进行了尝试。所以不确定这是否会回答您的问题。我发现对于用

final
注释的方法使用
@PreAuthorize
与不使用它是获得 200 或 403 返回的区别。不知道为什么会这样,但这就是我尝试过的。

我使用的示例代码(为了简洁起见,将其全部放在一个 Kotlin 文件中):

package com.example.demo

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
import org.springframework.security.config.web.server.ServerHttpSecurity
import org.springframework.security.config.web.server.invoke
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService
import org.springframework.security.core.userdetails.ReactiveUserDetailsService
import org.springframework.security.core.userdetails.User
import org.springframework.security.web.server.SecurityWebFilterChain
import org.springframework.stereotype.Service
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RestController
import reactor.core.publisher.Mono

@SpringBootApplication
class DemoApplication

fun main(args: Array<String>) {
    runApplication<DemoApplication>(*args)
}

@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity(useAuthorizationManager = true)
class WebAuthorizationConfig {
    @Bean
    fun userDetailsService(): ReactiveUserDetailsService {
        val userDetails = User.withDefaultPasswordEncoder()
            .username("user")
            .password("user")
            .roles("USER")
            .build()
        return MapReactiveUserDetailsService(userDetails)
    }

    @Bean
    fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
        return http {
            authorizeExchange {
                authorize(anyExchange, authenticated)
            }
            formLogin { }
            httpBasic { }
        }
    }
}

@RestController
class UserController(private val userService: UserService) {
    @GetMapping("/users/{uid}")
    final fun getUser(@PathVariable("uid") uid: String): Mono<String> {
        return userService.getUser(uid)
    }
}

@Service
class UserService {

    @PreAuthorize("denyAll()")
    // Notice no final keyword on this function - get expected 403. But if final keyword added, I get a 200.
    fun getUser(uid: String): Mono<String> {
        return Mono.just("user")
    }
}

测试

curl -u "user:user" http://localhost:8080/users/1 -v
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.