使用Autoproxy在AspectJ模式下无法使用@Secured注释

我正在尝试让我的Spring MVC应用程序与Spring @Secured注释和AspectJ自动代理一起使用,但它似乎不代理或识别我的@Secured注释。 我有一个像这样的控制器:

@Controller @RequestMapping("/") public class ApplicationController { private ApplicationFactory applicationFactory; @Inject public ApplicationController(ApplicationFactory applicationFactory) { super(); this.applicationFactory = applicationFactory; } @Secured("ROLE_USER") @ResponseBody @RequestMapping(method = GET) public Application getApplicationInfo() { return applicationFactory.buildApplication(this); } } 

一个Spring安全XML看起来像这样:

码:

      

以上是由no-xml Spring @Configuration组件加载的,如下所示:

 @Configuration @ComponentScan(basePackages = {"com.example"}) @EnableWebMvc @ImportResource("classpath:security.xml") public class ApplicationConfiguration extends WebMvcConfigurerAdapter { } 

反过来使用Servlet 3.0 WebApplicationInitializer加载:

 public class SpringMvcInitializer implements WebApplicationInitializer { private final AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); public void onStartup(ServletContext servletContext) throws ServletException { context.register(ApplicationConfiguration.class); servletContext.addListener(new ContextLoaderListener(context)); servletContext.addListener(new Log4jConfigListener()); final DelegatingFilterProxy proxy = new DelegatingFilterProxy("springSecurityFilterChain", context); FilterRegistration.Dynamic filter = servletContext.addFilter("securityFilter", proxy); filter.addMappingForUrlPatterns(EnumSet.of(REQUEST), false, "/*"); final DispatcherServlet servlet = new DispatcherServlet(context); ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", servlet); dispatcher.setLoadOnStartup(1); dispatcher.addMapping("/*"); } } 

但是,Spring Security没有检测到注释,我仍然可以在未经授权的情况下使用上面的安全端点。 根据Spring Security FAQ ,这可能是因为元素正在错误的应用程序上下文中加载,但我不知道如何使用上面的no-xml Spring配置来确保这一点。

我错过了什么吗? 我尝试将@EnableAspectJAutoProxy(proxyTargetClass = true)添加到我的应用程序配置中,但这也没有帮助。 有没有运行时编织或我是否必须使用编译时编织为我的应用程序启用基于注释的安全性?

在Spring中使用AOP时,您可以选择两种AOP实现:

  • Spring AOP实现不需要编织,但它仅适用于由Spring管理的bean并且有一些限制

  • AspectJ AOP实现可以适用于所有对象,并且没有Spring AOP的限制,但需要编译时或加载时编织

mode="aspectj"告诉Spring使用AspectJ进行AOP实现,因此在没有编织的情况下安全方面将无法工作。

术语“AspectJ自动代理”与使用AspectJ作为AOP实现无关 – 它是一个允许您在Spring AOP中使用AspectJ API(而不是实现)的function。

因此,在您的情况下,您可以使用Spring AOP实现,因为控制器是一个Spring bean,因此您应该删除mode="aspectj" 。 另请注意,您的控制器应该具有无参数构造函数 – 这是Spring AOP的限制之一。

为了扩展@ axtavt的答案, global-method-securitymode="aspectj"选项特别要求您的代码与spring-security-aspects模块中的AnnotationSecurityAspect编织在一起。

有一些示例代码可以演示它在使用中。 它只包含一个安全的bean和一些Junit测试,但代码是用AspectJ编译器编译的。 应用程序上下文还显示了与添加命名空间支持(注释掉的bean)之前所需的内容相比有多简单。