2015-02-03 14 views
7

मेरे पास एक आरईएसटी पूर्ण वेब सेवा है जो स्प्रिंग बूट 1.2.0-रिलीज के साथ लागू होती है जो कभी-कभी स्टार्टअप पर निम्न अपवाद फेंकता है।स्पष्ट वसंत बूट दौड़ की स्थिति डुप्लिकेट वसंत के कारण सुरक्षा सुरक्षा फ़िल्टरर

03-Feb-2015 11:42:23.697 SEVERE [localhost-startStop-1] org.apache.catalina.core.ContainerBase.addChildInternal ContainerBase.addChild: start: 
org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[]] 
     at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154) 
     at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:725) 
... 
Caused by: java.lang.IllegalStateException: Duplicate Filter registration for 'springSecurityFilterChain'. Check to ensure the Filter is only configured once. 
     at org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer.registerFilter(AbstractSecurityWebApplicationInitializer.java:215) 
     at org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer.insertSpringSecurityFilterChain(AbstractSecurityWebApplicationInitializer.java:147) 
... 

जब मैं "कभी कभी" कहते हैं, मैं बस बिलाव सर्वर (संस्करण 8.0.17) को पुन: प्रारंभ मतलब या तो इस अपवाद निकलेगा या सफलतापूर्वक मुद्दे के बिना लोड होगा।

यह स्प्रिंग बूट पर निर्मित एक सर्वलेट 3.0 एप्लिकेशन है, इसलिए हमारे पास पारंपरिक वेब.एक्सएमएल फ़ाइल नहीं है। इसके बजाए, हम जावा का उपयोग करके हमारे सर्वलेट को प्रारंभ करते हैं।

package com.v.dw.webservice; 

import org.springframework.boot.builder.SpringApplicationBuilder; 
import org.springframework.boot.context.web.SpringBootServletInitializer; 

public class WebXml extends SpringBootServletInitializer { 

    @Override 
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 
     return application.sources(ApplicationConfig.class); 
    } 
} 

हम यह भी विकास के दौरान mvn spring-boot:run आदेश का लाभ उठाने, और इस रेस स्थिति अभी तक जब इस तरह से चलाने के प्रकट करने के लिए है। हमारे विन्यास के "रूट" और मुख्य Maven द्वारा प्रयोग किया जाता विधि एक ही कक्षा में कर रहे हैं:

package com.v.dw.webservice; 

import javax.sql.DataSource; 

import org.springframework.beans.factory.annotation.Value; 
import org.springframework.boot.SpringApplication; 
import org.springframework.boot.actuate.autoconfigure.ManagementSecurityAutoConfiguration; 
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; 
import org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration; 
import org.springframework.boot.context.properties.ConfigurationProperties; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Primary; 

@SpringBootApplication 
@EnableAutoConfiguration(exclude = {ManagementSecurityAutoConfiguration.class, SecurityAutoConfiguration.class}) 
public class ApplicationConfig { 

    public static void main(String[] args) { 
     SpringApplication.run(ApplicationConfig.class, args); 
    } 

    @Value("${info.build.version}") 
    private String apiVersion; 

    @Bean 
    @Primary 
    @ConfigurationProperties(prefix="datasource.primary") 
    public DataSource primaryDataSource() { 
     return DataSourceBuilder.create().build(); 
    } 

} 

मैं परीक्षण के लिए एक कस्टम में स्मृति प्रमाणीकरण प्रदाता का उपयोग करने के लिए हमारे प्रमाणीकरण तर्क को सरल बनाने की कोशिश की है। जहां तक ​​मैं कह सकता हूं, क्लासपाथ पर यह एकमात्र कस्टम प्रमाणीकरण प्रदाता है, और हम एप्लिकेशन रूट पैकेज के बाहर कोई कॉन्फ़िगरेशन कक्षाएं आयात नहीं करते हैं।

दुर्भाग्य से प्रवेश स्प्रिंग और बिलाव द्वारा प्रदान की उत्पादन त्रुटि के आसपास किसी भी संदर्भ प्रदान करने में मदद नहीं करता है, इसलिए मैं यहाँ से AbstractSecurityWebApplictionInitializer स्रोत हथियाने की कोशिश की:

https://raw.githubusercontent.com/spring-projects/spring-security/rb3.2.5.RELEASE/web/src/main/java/org/springframework/security/web/context/AbstractSecurityWebApplicationInitializer.java

और मैं एक में registerFilter(...) विधि संशोधित System.out कॉल जोड़कर कुछ उपयोगी डीबग आउटपुट उत्पन्न करने का प्रयास करें।

private final void registerFilter(ServletContext servletContext, boolean insertBeforeOtherFilters, String filterName, Filter filter) { 
    System.out.println(">>>>>> Registering filter '" + filterName + "' with: " + filter.getClass().toString()); 
    Dynamic registration = servletContext.addFilter(filterName, filter); 
    if(registration == null) { 
     System.out.println(">>>>>> Existing filter '" + filterName + "' as: " + servletContext.getFilterRegistration(filterName).getClassName()); 
     throw new IllegalStateException("Duplicate Filter registration for '" + filterName +"'. Check to ensure the Filter is only configured once."); 
    } 
    registration.setAsyncSupported(isAsyncSecuritySupported()); 
    EnumSet<DispatcherType> dispatcherTypes = getSecurityDispatcherTypes(); 
    registration.addMappingForUrlPatterns(dispatcherTypes, !insertBeforeOtherFilters, "/*"); 
} 

जब यह विफल हो जाता है, तो डीबग आउटपुट केवल अपवाद से ठीक पहले उत्पन्न होता है। यह इंगित करता है registerFilter(...) विधि केवल एक बार कहा जाता है और वसंत लोड हो रहा है इस प्रक्रिया में अपेक्षाकृत देर से:

>>>>>> Registering filter 'springSecurityFilterChain' with: class org.springframework.web.filter.DelegatingFilterProxy 

    . ____   _   __ _ _ 
/\\/___'_ __ _ _(_)_ __ __ _ \ \ \ \ 
(()\___ | '_ | '_| | '_ \/ _` | \ \ \ \ 
\\/ ___)| |_)| | | | | || (_| | )))) 
    ' |____| .__|_| |_|_| |_\__, |//// 
=========|_|==============|___/=/_/_/_/ 
:: Spring Boot ::  (v1.2.0.RELEASE) 

यह पता चलता है सुरक्षा विन्यास हो रहा है:

>>>>>> Registering filter 'springSecurityFilterChain' with: class org.springframework.web.filter.DelegatingFilterProxy 
>>>>>> Existing filter 'springSecurityFilterChain' as: org.springframework.security.web.FilterChainProxy 

जब यह काम करता है, डिबग आउटपुट इस तरह दिखता है बहुत पहले लोडिंग प्रक्रिया में जब यह काम करता है बनाम बनाम काम करता है।

उत्तर

15

मुझे लगता है कि आपके आवेदन में AbstractSecurityWebApplicationInitializer का एक ठोस उप-वर्ग होना चाहिए। स्प्रिंग के सर्वलेट 3.0 समर्थन को यह WebApplicationInitializer कार्यान्वयन मिलेगा और इसे कॉल करें जब टॉमकैट आपके ऐप को शुरू करेगा। यह स्प्रिंग सिक्योरिटी के फ़िल्टर को पंजीकृत करने का प्रयास ट्रिगर करता है। आपके पास WebXml कक्षा भी है जो SpringBootServletInitializer फैली हुई है। यह भी WebApplicationInitializer है जिसे टॉमकैट आपके ऐप को शुरू करने पर कॉल किया जाएगा। स्प्रिंग बूट के ऑटो-कॉन्फ़िगरेशन समर्थन के कारण यह स्प्रिंग सिक्योरिटी के फ़िल्टर को पंजीकृत करने का प्रयास भी ट्रिगर करता है।

आपकी WebXml कक्षा एक आदेश घोषित नहीं करती है (यह वसंत के Ordered इंटरफ़ेस को लागू नहीं करती है और इसे @Order के साथ एनोटेट नहीं किया गया है)। मुझे लगता है कि यह आपके AbstractSecurityWebApplicationInitializer सबक्लास के बारे में भी सच है। इसका मतलब है कि दोनों के पास एक ही ऑर्डर (डिफ़ॉल्ट) है इसलिए स्प्रिंग किसी भी क्रम में उन्हें कॉल करने के लिए स्वतंत्र है।आपका आवेदन तब काम करता है जब आपका AbstractSecurityWebApplicationInitializer सबक्लास पहले चला जाता है क्योंकि स्प्रिंग बूट पहले से मौजूद फ़िल्टर का सहिष्णु है। यदि विफल रहता है जब स्प्रिंग बूट पहले AbstractSecurityWebApplicationInitializer के रूप में पहले सहिष्णु नहीं है।

यह सब कहकर, जैसा कि आप स्प्रिंग बूट का उपयोग कर रहे हैं, आपको अपने AbstractSecurityWebApplicationInitializer की आवश्यकता भी नहीं हो सकती है, इसलिए सबसे आसान समाधान शायद इसे हटाने के लिए है। यदि आप यह आवश्यकता क्यों है तो आपको दोनों यह और WebXml एक आदेश (@Order के साथ उनकी व्याख्या या लागू Ordered) ताकि WebXml हमेशा अपने AbstractSecurityWebApplicationInitializer उपवर्ग के बाद कहा जाने की गारंटी है आवंटित करने चाहिए।

0

के बाद वसंत बूट प्रलेखन आप अपने अनुप्रयोग विन्यास में एनोटेशन @EnableWebMvcSecurity जोड़कर डिफ़ॉल्ट सुरक्षा विन्यास वसंत बूट द्वारा लोड अक्षम करना चाहिए (75.2 Change the AuthenticationManager and add user accounts देखें) और की तुलना में आप इस तरह एक वेब सुरक्षा एडाप्टर कॉन्फ़िगर करना चाहिए:

@Bean 
WebSecurityConfigurerAdapter webSecurityAdapter() { 
    WebSecurityConfigurerAdapter adapter = new WebSecurityConfigurerAdapter() { 
      @Override 
      protected void configure(HttpSecurity http) throws Exception { 
       http.... 
संबंधित मुद्दे