2012-02-16 4 views
2

Я кодирую веб-сайт, который будет почти полностью защищен логином (для этого я использую Spring Security). Существуют определенные страницы, которые не защищены, хотя (домашняя страница, страница входа, страница регистрации, страница забытых паролей и т. Д.), И я пытаюсь достичь:Аспект не выполнен весной

  • Если пользователь не зарегистрирован в при доступе к этим небезопасные страницы, показать им, как правило,
  • Если пользователь уже вошел в систему, перенаправление на главную страницу (или на странице, указанной в элементе redirectTo аннотаций)

конечно Я хочу, чтобы это не было сделано для каждого метода контроллера:

if(loggedIn()) 
{ 
    // Redirect 
} 
else 
{ 
    // Return the view 
} 

И по этой причине я хотел бы использовать АОП.

Я создал аннотацию @NonSecured, и я закодирован следующий аспект:

@Aspect 
public class LoggedInRedirectAspect 
{ 
    @Autowired 
    private UserService userService; 

    @Around("execution(@my.package.annotation.NonSecured * *(..))") 
    public void redirect(ProceedingJoinPoint point) throws Throwable 
    { 
     System.out.println("Test"); 
     point.proceed(); 
    } 
} 

Пример аннотированного метод:

@Controller 
@RequestMapping("/") 
public class HomeController 
{ 
    @NonSecured(redirectTo = "my-profile") 
    @RequestMapping(method = RequestMethod.GET) 
    public String index(Model model, 
         HttpServletRequest request) throws Exception 
    { 
     // Show home page 
    } 
} 

applicationContext.xml важные биты:

<context:annotation-config /> 
<context:component-scan base-package="my.package" /> 

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /> 

<bean id="loggedInRedirectAspect" class="my.package.aspect.LoggedInRedirectAspect" /> 
<aop:aspectj-autoproxy proxy-target-class="true"> 
    <aop:include name="loggedInRedirectAspect" /> 
</aop:aspectj-autoproxy> 

Проблема заключается в том что метод redirect(...) в аспекте никогда не получает calle д. Аспекты в целом работают нормально, на самом деле будет вызван следующий метод в аспекте: Следующий совет вызывается, но не вызывается для методов контроллера.

@Around("execution(* *(..))") 
public void redirect(ProceedingJoinPoint point) throws Throwable 
{ 
    point.proceed(); 
} 

Я делаю что-то не так в моем pointcut?

спасибо.

Обновление: Последний фрагмент в этом вопросе вызван, но по-прежнему не вызван для методов контроллера.

ответ

6

@satoshi, я думаю, что проблема, с которой вы сталкиваетесь, заключается в том, что вы используете Spring-AOP и можете создавать прокси AOP только для beans с интерфейсами - и в вашем случае контроллеры не имеют интерфейса.

Исправление может использовать время компиляции время/загрузки ткачества с использованием AspectJ и не использовать Spring AOP или иметь CGLIB банки в пути к классам и заставить CGLIB создание прокси на основе:

<aop:aspectj-autoproxy proxy-target-class="true"/> 

Обновление: время компиляции ткачество может быть сделано с использованием Maven плагин, конфигурация showWeaveInfo покажет, какие именно классы были сотканы:

<plugin> 
    <groupId>org.codehaus.mojo</groupId> 
    <artifactId>aspectj-maven-plugin</artifactId> 
    <version>1.0</version> 
    <dependencies> 
     <dependency> 
      <groupId>org.aspectj</groupId> 
      <artifactId>aspectjrt</artifactId> 
      <version>1.6.10</version> 
     </dependency> 
     <dependency> 
      <groupId>org.aspectj</groupId> 
      <artifactId>aspectjtools</artifactId> 
      <version>1.6.10</version> 
     </dependency> 
    </dependencies> 
    <executions> 
     <execution> 
      <goals> 
       <goal>compile</goal> 
       <goal>test-compile</goal> 
      </goals> 
     </execution> 
    </executions> 
    <configuration> 
     <outxml>true</outxml> 
     <verbose>true</verbose> 
     <showWeaveInfo>true</showWeaveInfo> 
     <aspectLibraries> 
      <aspectLibrary> 
       <groupId>org.springframework</groupId> 
       <artifactId>spring-aspects</artifactId> 
      </aspectLibrary> 
     </aspectLibraries> 
     <source>1.6</source> 
     <target>1.6</target> 
    </configuration> 
</plugin> 
+0

Спасибо @BijuKunjummen, но это не решило проблему – satoshi

+0

Можете ли вы отладить с точкой останова в классе контроллера @satoshi - если прокси-сервер был успешно создан cglib, как в вашем случае, вы должны увидеть он отражается в типе вашего класса контроллера в переменных отладки (с затмением). Если тип не является прокси-сервером, то CGLIB не вступил в силу - я бы предложил использовать время компиляции - тогда у вас будет многословная опция ткача, чтобы посмотреть, какие классы действительно сотканы. –

+0

Вы правы @BijuKunjummen, похоже, что прокси-сервер не создается для контроллера (тип - HomeController, и я не вижу никакого вызова какого-либо метода прокси/aop в трассировке стека). Итак, как вы говорите, CGLIB не вступил в силу. Извините, но я новичок в Spring, как мне может помочь компиляция времени? И как я могу его использовать?Спасибо – satoshi

0

Обычно я использую перехватчик, а не аспект для этой цели. Например, создайте RequestInitializeInterceptor, который будет проверять принципала безопасности и перенаправлять соответственно. Аспекты - это избыток этой работы. Перехватчик будет выступать в качестве переднего контроллера для каждого запроса конкретным контроллерам и решить, разрешено ли ему передавать запрос или нет.

public class RequestInitializeInterceptor extends HandlerInterceptorAdapter { 

    // Obtain a suitable logger. 
    private static Log logger = LogFactory 
     .getLog(RequestInitializeInterceptor.class); 

    /** 
    * In this case intercept the request BEFORE it reaches the controller 
    */ 
    @Override 
    public boolean preHandle(HttpServletRequest request, 
     HttpServletResponse response, Object handler) throws Exception { 
    try { 

     logger.info("Intercepting: " + request.getRequestURI()); 

     // Your logic to redirect accordingly 
    if (userAuthenticated) { 
     response.sendRedirect(URL); 
     return false; 
    } 
     return true; 
    } catch (SystemException e) { 
     logger.info("request update failed"); 
     return false; 
    } 
    } 
} 

Надеюсь, это поможет.

+0

Спасибо за ваш ответ, @Abhi. Наверное, я опустил важный момент. В аннотации '@ NonSecured' есть элемент redirectTo, где я могу указать, где перенаправить запрос, когда пользователь уже выполнил вход. Я обновил исходный вопрос. Я не вижу, как я могу использовать перехватчик, учитывая это требование ... – satoshi

+0

Перехватчик перехватит все запросы на получение, и вы можете получить принципала безопасности от запроса, чтобы оценить, проверен ли пользователь или нет, и в зависимости от состояния пользователя просто сделайте response.sendredirect – Abhi

+0

Но это означает, что я должен закодировать всю логику решения в перехватчике, и я думаю, что это очень грязный способ сделать это, не так ли? Имея много 'if' только для того, чтобы определить, нуждается ли запрос в перенаправлении ... – satoshi

0

Что работал меня, пожалуйста, гр Хека следующие пункты:

  • aspectjweaver.jar находится на пути к классам (версия 1.6.8 или более поздняя версия)
  • Аспект класс с аннотацией как @Aspect и @Component
  • Вы позволили весной AspectJ-авто-прокси

Java конфигурации:

@Configuration 
@ComponentScan("io.mc.springaspects") 
@EnableAspectJAutoProxy 
public class SpringConfiguration { 
} 

Формат:

@Aspect 
@Component 
public class AnnotationAspect { 
    ... 
} 

Maven:

<dependency> 
    <groupId>org.aspectj</groupId> 
    <artifactId>aspectjweaver</artifactId> 
    <version>1.8.9</version> 
</dependency> 
Смежные вопросы