2011-12-27 40 views
9

Hành vi mặc định của bộ xử lý kênh là gửi sendRedirect (chuyển hướng tạm thời bằng mã 302). Tôi cần phải thay đổi hành vi này để chuyển hướng vĩnh viễn (301) được thực hiện thay vì chuyển hướng 302. Tôi cố gắng để làm như sau:Ghi đè ChannelProcessingFilter bằng Spring Security 3.0.5 không hoạt động

  1. Tạo một ChannelProcessingFilter tùy chỉnh bằng cách mở rộng ChannelProcessingFilter:

    public class MyChannelProcessingFilter extends ChannelProcessingFilter{ 
        //No implementation, I needed this to just make sure that a custom filter is created and I can configure it as a custom filter in the xml file. 
    } 
    
  2. Tạo một EntryPoint tùy chỉnh bằng cách mở rộng AbstractRetryEntryPoint

    public class RetryWithHttpsEntryPoint extends org.springframework.security.web.access.channel.AbstractRetryEntryPoint { 
        private PortResolver portResolver = new PortResolverImpl(); 
        private final String scheme ="https://"; 
        /** The standard port for the scheme (80 for http, 443 for https) */ 
        private final int standardPort = 443; 
    
        public RetryWithHttpsEntryPoint() { 
         super("https://", 443); 
        } 
    
        @Override 
        public void commence(HttpServletRequest request, HttpServletResponse res) throws IOException, ServletException { 
         String queryString = request.getQueryString(); 
         String redirectUrl = request.getRequestURI() + ((queryString == null) ? "" : ("?" + queryString)); 
    
         Integer currentPort = new Integer(portResolver.getServerPort(request)); 
         Integer redirectPort = getMappedPort(currentPort); 
    
         if (redirectPort != null) { 
          boolean includePort = redirectPort.intValue() != standardPort; 
    
          redirectUrl = scheme + request.getServerName() + ((includePort) ? (":" + redirectPort) : "") + redirectUrl; 
         } 
    
         if (logger.isDebugEnabled()) { 
          logger.debug("Redirecting to: " + redirectUrl); 
         } 
    
         res.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); 
         res.setHeader("Location", redirectUrl); 
         res.setHeader("Connection", "close"); 
        } 
    
        protected Integer getMappedPort(Integer mapFromPort) { 
         return getPortMapper().lookupHttpsPort(mapFromPort); 
        } 
    } 
    
  3. Configure cùng trong tệp applicationContext-security.xml. Tôi đặt các tập tin xml hoàn chỉnh cho các bạn tham khảo (loại bỏ những phần không cần thiết. Nếu bạn yêu cầu các bộ phận khác làm cho tôi biết)

    <?xml version="1.0" encoding="UTF-8"?> 
    
    <beans xmlns="http://www.springframework.org/schema/beans" 
        xmlns:security="http://www.springframework.org/schema/security" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:util="http://www.springframework.org/schema/util" 
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
          http://www.springframework.org/schema/security 
          http://www.springframework.org/schema/security/spring-security-3.0.3.xsd 
          http://www.springframework.org/schema/util 
          http://www.springframework.org/schema/util/spring-util.xsd"> 
    
        <security:http auto-config="false" 
          entry-point-ref="authenticationProcessingFilterEntryPoint" 
          access-decision-manager-ref="accessDecisionManager" > 
         <security:intercept-url pattern="/activ8/protectedCheckEligibility.html**" access="user" requires-channel="https"/> 
         <security:intercept-url pattern="/siteMap.html" access="ROLE_ANONYMOUS,user,admin" requires-channel="http"/> 
         <security:intercept-url pattern="/privacyPolicy.html" access="ROLE_ANONYMOUS,user,admin" requires-channel="http"/> 
         <!-- other urls configured over here --> 
         <security:intercept-url pattern="/*.jsp" access="ROLE_ANONYMOUS,admin,user" requires-channel="https"/> 
         <security:intercept-url pattern="/**/*.html**" access="ROLE_ANONYMOUS,user,admin" requires-channel="https"/> 
         <security:intercept-url pattern="/fb_activities.html**" access="parent" />  
    
         <security:remember-me key="appfuseRocks" /> 
         <security:custom-filter position="SWITCH_USER_FILTER" ref="careSwitchUserProcessingFilter"/> 
         <security:custom-filter position="FORM_LOGIN_FILTER" ref="myCustomAuthenticationProcessingFilter"/> 
         <!-- configured the custom channel filter over here --> 
         <security:custom-filter position="CHANNEL_FILTER" ref="myChannelProcessingFilter"/> 
        </security:http> 
    
        <bean id="myChannelProcessingFilter" class="com.my.webapp.filter.myChannelProcessingFilter"> 
         <property name="channelDecisionManager" ref="channelDecisionManager" /> 
         <property name="securityMetadataSource"> 
          <security:filter-security-metadata-source path-type="ant"> 
           <security:intercept-url pattern="/**" access="REQUIRES_INSECURE_CHANNEL" /> 
          </security:filter-security-metadata-source> 
         </property> 
        </bean> 
    
        <bean id="channelDecisionManager" class="org.springframework.security.web.access.channel.ChannelDecisionManagerImpl"> 
         <property name="channelProcessors"> 
          <list> 
           <ref bean="secureChannelProcessor"/> 
          </list> 
         </property> 
        </bean> 
    
        <bean id="secureChannelProcessor" class="org.springframework.security.web.access.channel.SecureChannelProcessor"> 
         <property name="entryPoint" ref="secureChannelEntryPoint"/> 
         <!-- <property name="portMapper" ref="portMapper" /> --> 
         <property name="secureKeyword" value="REQUIRES_SECURE_CHANNEL"/> 
        </bean> 
    
        <bean id="secureChannelEntryPoint" class="com.my.webapp.filter.RetryWithHttpsEntryPoint"/> 
    
        <!-- lot of other configuratons... removed --> 
    
    </beans> 
    

Tôi nhận được lỗi sau khi tôi cố gắng chạy tomcat của tôi:

 
ERROR 2011-12-26 21:13:21,569 [ina].[localhost].[/]]: Exception sending context initialized event to listener instance of class com.kajeet.webapp.listener.StartupListener 
org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Filter beans '' and 'Root bean: class [org.springframework.security.web.access.channel.ChannelProcessingFilter]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null' have the same 'order' value. When using custom filters, please make sure the positions do not conflict with default filters. Alternatively you can disable the default filters by removing the corresponding child elements from and avoiding the use of . 
    Offending resource: ServletContext resource [/WEB-INF/applicationContext-security.xml] 
    at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68) 
    at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85) 
    at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:72) 
    at org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.checkFilterChainOrder(HttpSecurityBeanDefinitionParser.java:196) 
    at org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.parse(HttpSecurityBeanDefinitionParser.java:132) 
    at org.springframework.security.config.SecurityNamespaceHandler.parse(SecurityNamespaceHandler.java:86) 
    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1335) 
    at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1325) 
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:135) 
    at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:93) 
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493) 
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390) 
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334) 
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302) 
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:143) 
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:178) 
    at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:149) 
    at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:124) 
    at org.springframework.web.context.support.XmlWebApplicationContext.loadBeanDefinitions(XmlWebApplicationContext.java:93) 
    at org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory(AbstractRefreshableApplicationContext.java:130) 
    at org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:467) 
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:397) 
    at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:276) 
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:197) 
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47) 
    at com.kajeet.webapp.listener.StartupListener.contextInitialized(StartupListener.java:51) 
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3764) 
    at org.apache.catalina.core.StandardContext.start(StandardContext.java:4216) 
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:760) 
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:740) 
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:544) 
    at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:920) 
    at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:883) 
    at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:492) 
    at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1138) 
    at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311) 
    at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:120) 
    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1022) 
    at org.apache.catalina.core.StandardHost.start(StandardHost.java:736) 
    at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1014) 
    at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443) 
    at org.apache.catalina.core.StandardService.start(StandardService.java:448) 
    at org.apache.catalina.core.StandardServer.start(StandardServer.java:700) 
    at org.apache.catalina.startup.Catalina.start(Catalina.java:552) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:295) 
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:433) 

Tôi cũng đã ghi đè các bộ lọc khác và không phàn nàn về các bộ lọc đó. Ứng dụng này đã chạy hoàn toàn tốt trước đây. Chúng tôi đã có yêu cầu bổ sung này và do đó tôi đã thêm bộ lọc mới và chạy vào các lỗi như vậy. Phương pháp thứ hai mà tôi đã thử chỉ là cấu hình ChannelProcessingFilter mặc định trong XML, vì trong Spring 3.0, các bộ lọc được tự động gọi, tôi đã ấn tượng rằng tôi có thể cấu hình chúng trong tệp XML và mùa xuân sẽ tự động tải chúng, nhưng nó không:

<?xml version="1.0" encoding="UTF-8"?> 

    <beans xmlns="http://www.springframework.org/schema/beans" 
     xmlns:security="http://www.springframework.org/schema/security" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xmlns:util="http://www.springframework.org/schema/util" 
     xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
       http://www.springframework.org/schema/security 
       http://www.springframework.org/schema/security/spring-security-3.0.3.xsd 
       http://www.springframework.org/schema/util 
       http://www.springframework.org/schema/util/spring-util.xsd"> 

     <security:http auto-config="false" 
       entry-point-ref="authenticationProcessingFilterEntryPoint" 
       access-decision-manager-ref="accessDecisionManager" > 
      <security:intercept-url pattern="/activ8/protectedCheckEligibility.html**" access="user" requires-channel="https"/> 
      <security:intercept-url pattern="/siteMap.html" access="ROLE_ANONYMOUS,user,admin" requires-channel="http"/> 
      <security:intercept-url pattern="/privacyPolicy.html" access="ROLE_ANONYMOUS,user,admin" requires-channel="http"/> 
      <!-- other urls configured over here --> 
      <security:intercept-url pattern="/*.jsp" access="ROLE_ANONYMOUS,admin,user" requires-channel="https"/> 
      <security:intercept-url pattern="/**/*.html**" access="ROLE_ANONYMOUS,user,admin" requires-channel="https"/> 
      <security:intercept-url pattern="/fb_activities.html**" access="parent" />  

      <security:remember-me key="appfuseRocks" /> 
      <security:custom-filter position="SWITCH_USER_FILTER" ref="careSwitchUserProcessingFilter"/> 
      <security:custom-filter position="FORM_LOGIN_FILTER" ref="myCustomAuthenticationProcessingFilter"/> 
     </security:http> 

     <bean id="channelDecisionManager" class="org.springframework.security.securechannel.ChannelDecisionManagerImpl"> 
      <property name="channelProcessors"> 
       <list> 
        <ref bean="secureChannelProcessor"/> 
        <ref bean="insecureChannelProcessor"/> 
       </list> 
      </property> 
     </bean> 

     <bean id="secureChannelProcessor" class="org.springframework.security.web.access.channel.SecureChannelProcessor"/> 
     <bean id="insecureChannelProcessor" class="org.springframework.security.web.access.channel.InsecureChannelProcessor"/> 

     <!-- lot of other configuratons... removed --> 

    </beans> 

Mọi trợ giúp sẽ được đánh giá cao. Tôi không phải là một chuyên gia mùa xuân, nhưng tôi đã làm một số công việc trên nó, một con trỏ hoặc hai chắc chắn có thể giúp tôi giải quyết vấn đề này. Cảm ơn bạn trước

+0

On nghiên cứu thêm , Tôi đã biết rằng điều này không yêu cầu mở rộng ChannelProcessingFilter, vấn đề tôi tìm thấy là SecureChannelProce ssor được initailzed hai lần, một lần với các giá trị mặc định và lần thứ hai với các giá trị tùy chỉnh là một phần của XML. Khi áp dụng các quy tắc, nó chỉ sử dụng quy tắc với giá trị mặc định. Có vẻ như tôi đang thiếu một liên kết rất nhỏ ở đâu đó. –

Trả lời

2

Giải pháp:

Vấn đề là chúng ta không thể có cả an ninh: http cũng như myChannelProcessingFilter (người tôi đã ghi đè) để đối phó với đối số truy cập của an ninh: intercept-url, do đó tôi đã xóa thẻ http và thêm điều truy cập vào myChannelProcessingFilter, nơi tôi muốn nó xử lý. XML đã giải quyết nó theo sau

<?xml version="1.0" encoding="UTF-8"?> 

<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:security="http://www.springframework.org/schema/security" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:util="http://www.springframework.org/schema/util" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
      http://www.springframework.org/schema/security 
      http://www.springframework.org/schema/security/spring-security-3.0.3.xsd 
      http://www.springframework.org/schema/util 
      http://www.springframework.org/schema/util/spring-util.xsd"> 

    <!-- 
     The http element responsible for creating a FilterChainProxy and the filter beans which it uses. 
     Common problems like incorrect filter ordering are no longer an issue as the filter positions are predefined. 
    --> 
    <security:http auto-config="false" 
      entry-point-ref="authenticationProcessingFilterEntryPoint" 
      access-decision-manager-ref="accessDecisionManager" > 

     <security:custom-filter position="CHANNEL_FILTER" ref="channelProcessingFilter"/> 

     <security:intercept-url pattern="/*.html*" access="ROLE_ANONYMOUS,admin,user" /> 
     <security:intercept-url pattern="/*.jsp" access="ROLE_ANONYMOUS,admin,user" /> 
     <security:intercept-url pattern="/**/*.html**" access="ROLE_ANONYMOUS,user,admin" /> 


    </security:http> 

    <bean id="channelProcessingFilter" class="org.springframework.security.web.access.channel.ChannelProcessingFilter"> 
     <property name="channelDecisionManager" ref="channelDecisionManager"/> 
     <property name="securityMetadataSource"> 
     <security:filter-security-metadata-source path-type="ant"> 
      <security:intercept-url pattern="/*.jsp**" access="REQUIRES_SECURE_CHANNEL" /> 
      <security:intercept-url pattern="/**/*.html**" access="REQUIRES_SECURE_CHANNEL" /> 
     </security:filter-security-metadata-source> 
     </property> 
    </bean> 

    <bean id="channelDecisionManager" class="org.springframework.security.web.access.channel.ChannelDecisionManagerImpl"> 
     <property name="channelProcessors"> 
      <list> 
       <ref bean="secureProcessor"/> 
       <ref bean="insecureProcessor"/> 
      </list> 
     </property> 
    </bean> 

    <bean id="secureProcessor" class="org.springframework.security.web.access.channel.SecureChannelProcessor" > 
     <property name="entryPoint" ref="retryWithHttps"/> 
    </bean> 

    <bean id="insecureProcessor" class="org.springframework.security.web.access.channel.InsecureChannelProcessor"> 
     <property name="entryPoint" ref="retryWithHttp"/> 
    </bean> 

    <bean id="retryWithHttps" class="com.my.webapp.filter.RetryWithHttpsEntryPoint" /> 
    <bean id="retryWithHttp" class="com.my.webapp.filter.RetryWithHttpEntryPoint" /> 

</beans> 
0

Tôi tìm thấy một cách khác để đạt được điều tương tự với mã và độ phức tạp ít hơn nhiều. Bạn chỉ cần sử dụng BeanPostProcessor để nhận SecureChannelProcessorInsecureChannelProcessor và sau đó đặt điểm nhập của riêng bạn trên chúng. Bằng cách đó, bạn vẫn có thể sử dụng các giá trị mặc định trên mọi thứ khác.

Các BeanPostProcessor:

@Component 
public class ChannelProcessorsPostProcessor implements BeanPostProcessor { 

    @Override 
    public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException { 

     if (bean instanceof SecureChannelProcessor) ((SecureChannelProcessor)bean).setEntryPoint(new MyEntryRetryPoint("https://", 443)); 
     else if (bean instanceof InsecureChannelProcessor) ((InsecureChannelProcessor)bean).setEntryPoint(new MyEntryRetryPoint("http://", 80)); 

     return bean; 
    } 

    @Override 
    public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException { 

     return bean; 
    } 
} 
0

Tôi nghĩ rằng nó tốt hơn để viết một chiến lược chuyển hướng:

@Component 
public class PermanentRedirectStrategy implements RedirectStrategy { 
    private boolean contextRelative; 

    @Override 
    public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url) throws IOException { 
     response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); 
     response.setHeader("Location", response.encodeRedirectURL(calculateRedirectUrl(request.getContextPath(), url))); 
    } 

    /** 
    * Unfortunately DefaultRedirectStrategy.calculateRedirectUrl is private 
    * If this weren't the case, we could extend this class from DefaultRedirectStrategy 
    * to use its method directly without copying it 
    */ 
    private String calculateRedirectUrl(String contextPath, String url) { 
     if (!UrlUtils.isAbsoluteUrl(url)) { 
      if (contextRelative) { 
       return url; 
      } else { 
       return contextPath + url; 
      } 
     } 

     // Full URL, including http(s):// 

     if (!contextRelative) { 
      return url; 
     } 

     // Calculate the relative URL from the fully qualified URL, minus the last 
     // occurence of the scheme and base context 
     url = url.substring(url.lastIndexOf("://") + 3); // strip off scheme 
     url = url.substring(url.indexOf(contextPath) + contextPath.length()); 

     if (url.length() > 1 && url.charAt(0) == '/') { 
      url = url.substring(1); 
     } 

     return url; 
    } 
} 

và sau đó đặt nó vào điểm mấu chốt hiện có:

@Component 
public class ChannelProcessorsPostProcessor implements BeanPostProcessor { 
    @Autowired 
    private RedirectStrategy permanentRedirectStrategy; 

    @Override 
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 
     ChannelEntryPoint entryPoint = null; 

     if (bean instanceof SecureChannelProcessor) { 
      entryPoint = ((SecureChannelProcessor) bean).getEntryPoint(); 
     } else if (bean instanceof InsecureChannelProcessor) { 
      entryPoint = ((InsecureChannelProcessor) bean).getEntryPoint(); 
     } 

     if (entryPoint != null && AbstractRetryEntryPoint.class.isAssignableFrom(entryPoint.getClass())) { 
      ((AbstractRetryEntryPoint) entryPoint).setRedirectStrategy(permanentRedirectStrategy); 
     } 

     return bean; 
    } 

    @Override 
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 
     return bean; 
    } 
} 
Các vấn đề liên quan