- 
                Notifications
    You must be signed in to change notification settings 
- Fork 41.6k
Description
This is a followon to #16398, which was closed due to lack of reproducability, based on research for spring-projects/spring-framework#26603. In short, interoperability between Spring Security and Spring MVC requires class-based proxying to be in effect, but spring.aop.proxy-target-class does not apply its settings until after the controller beans are already created.
Starting from a blank (Groovy) project from Initializr with Boot 2.4.3, I have these classes:
@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled = true)
class DemoApplication {
  static void main(String[] args) {
    SpringApplication.run(DemoApplication, args)
  }
}@RestController
class DemoController implements Supplier<String> {
  // Supplier is here to get the infrastructure to decide it can use a JDK proxy
  @RequestMapping('/demo')
  @PreAuthorize('true')
  def demo() {
    'Hello'
  }
  @Override
  String get() {
    demo()
  }
}@SpringBootTest
@AutoConfigureMockMvc
class DemoApplicationTests {
  @Autowired
  MockMvc mockMvc
  @Test
  @WithMockUser
  void hello() {
    mockMvc.perform(get('http://localhost/hello')).andExpect(status().isOk())
  }
}and this line in application.properties:
spring.aop.proxy-target-class: true
The auto-config report happily indicates that ClassProxyingConfiguration is active, but the constructor for that class, which applies its rules by side-effect, is not called until after the controller is already instantiated using the then-configuration of "use JDK proxy". This in turn triggers the cascade of looking at the wrong class (the proxy interface) for mappings, failing to find anything, and returning a 404.
The "simple" workaround of @EnableAspectJAutoProxy(proxyTargetClass = true) requires pulling in the whole AspectJ infrastructure instead of using CGLib.