-
Notifications
You must be signed in to change notification settings - Fork 41.5k
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.