@ Защищенные аннотации не работают в режиме AspectJ с Autoproxy

Я пытаюсь заставить мое приложение 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);
    }

}

И пружинный 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> Элемент загружается в неправильном контексте приложения, но я не знаю, как это обеспечить, используя вышеупомянутую конфигурацию Spring без no-xml.

Я что-то пропустил? Я попытался добавить @EnableAspectJAutoProxy(proxyTargetClass = true) в конфигурацию моего приложения, но это тоже не помогло. Есть ли в любом случае переплетение времени выполнения или мне придется использовать переплетение времени компиляции для обеспечения безопасности на основе аннотаций для моего приложения?

2 ответа

Решение

При использовании AOP с Spring вы можете выбрать одну из двух реализаций AOP:

  • Реализация Spring AOP не требует ткачества, но она применима только к bean-компонентам, управляемым Spring, и имеет некоторые ограничения

  • Реализация AspectJ AOP может работать для всех объектов и не имеет ограничений Spring AOP, но требует переплетения во время компиляции или загрузки

mode="aspectj" говорит Spring использовать AspectJ для реализации AOP, поэтому аспект безопасности не будет работать без переплетения в вашем случае.

Термин "автоматическое проксирование AspectJ" не имеет ничего общего с использованием AspectJ в качестве реализации AOP - это функция, которая позволяет использовать AspectJ API (а не реализацию) с Spring AOP.

Итак, в вашем случае вы можете использовать реализацию Spring AOP, потому что контроллер - это bean-компонент Spring, поэтому вы должны удалить mode="aspectj", Также обратите внимание, что ваш контроллер должен иметь конструктор без аргументов - это одно из ограничений Spring AOP.

Чтобы немного расширить ответ @axtavt, mode="aspectj" вариант в global-method-security конкретно требует, чтобы ваш код был сплетен с AnnotationSecurityAspect от spring-security-aspects модуль.

Есть некоторый пример кода, который демонстрирует его использование. Он состоит только из защищенного компонента и некоторого теста Junit, но код компилируется с помощью компилятора AspectJ. Контекст приложения также показывает, насколько просто он сравнивается с тем, что требовалось до того, как была добавлена ​​поддержка пространства имен (закомментированные компоненты).

Другие вопросы по тегам