2

我试图让我的 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 Security XML:

代码:

  <security:global-method-security secured-annotations="enabled" mode="aspectj" proxy-target-class="true" />

  <security:http auto-config="true" use-expressions="true">
    <security:http-basic/>
  </security:http>

上面是由一个 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,这可能是因为<global-method-security>在错误的应用程序上下文中加载了元素,但我不知道如何使用上述 no-xml Spring 配置来确保这一点。

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

4

2 回答 2

6

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

  • Spring AOP 实现不需要编织,但只适用于 Spring 管理的 bean,有一定的局限性

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

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

术语“AspectJ 自动代理”与使用 AspectJ 作为 AOP 实现无关——它是一个允许您将 AspectJ API(而不是实现)与 Spring AOP 一起使用的特性。

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

于 2012-07-09T18:45:32.863 回答
4

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

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

于 2012-07-13T17:00:23.797 回答