복붙노트

[SPRING] Spring의 인증 필터 내에서 서비스를 자동 응답 할 수 없습니다.

SPRING

Spring의 인증 필터 내에서 서비스를 자동 응답 할 수 없습니다.

토큰으로 사용자를 인증하려고하지만 AuthenticationTokenProcessingFilter 내부에서 내 서비스를 자동 연결하려고하면 null 포인터 예외가 발생합니다. autowired 서비스가 null이기 때문에 어떻게이 문제를 해결할 수 있습니까?

내 AuthenticationTokenProcessingFilter 클래스

@ComponentScan(basePackages = {"com.marketplace"})
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {

    @Autowired
    @Qualifier("myServices")
    private MyServices service;

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        @SuppressWarnings("unchecked")
        Map<String, String[]> parms = request.getParameterMap();

        if (parms.containsKey("token")) {
            try {
                String strToken = parms.get("token")[0]; // grab the first "token" parameter

                User user = service.getUserByToken(strToken);
                System.out.println("Token: " + strToken);

                DateTime dt = new DateTime();
                DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
                DateTime createdDate = fmt.parseDateTime(strToken);
                Minutes mins = Minutes.minutesBetween(createdDate, dt);


                if (user != null && mins.getMinutes() <= 30) {
                    System.out.println("valid token found");

                    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
                    authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));

                    UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(user.getEmailId(), user.getPassword());
                    token.setDetails(new WebAuthenticationDetails((HttpServletRequest) request));
                    Authentication authentication = new UsernamePasswordAuthenticationToken(user.getEmailId(), user.getPassword(), authorities); //this.authenticationProvider.authenticate(token);

                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }else{
                    System.out.println("invalid token");
                }
            } catch(Exception e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("no token found");
        }
        // continue thru the filter chain
        chain.doFilter(request, response);
    }
}

나는 내 App Config에서 다음을 추가하려고 시도했다.

@Bean(name="myServices")
    public MyServices stockService() {
        return new MyServiceImpl();
    }

내 AppConfig 주석은 다음과 같습니다.

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.marketplace")
public class AppConfig extends WebMvcConfigurerAdapter {

해결법

  1. ==============================

    1.필터의 종속성 삽입은 즉시 사용할 수 없습니다. GenericFilterBean을 사용하더라도 Servlet Filter는 봄에 관리되지 않습니다. javadocs에서 언급했듯이

    필터의 종속성 삽입은 즉시 사용할 수 없습니다. GenericFilterBean을 사용하더라도 Servlet Filter는 봄에 관리되지 않습니다. javadocs에서 언급했듯이

    평범한 영어로 봄이 서비스를 주입 할 것으로 기대할 수는 없지만 첫 번째 호출에서 스프링을 설정하는 것이 좋습니다. 예 :

    public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
        private MyServices service;
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            if(service==null){
                ServletContext servletContext = request.getServletContext();
                WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
                service = webApplicationContext.getBean(MyServices.class);
            }
            your code ...    
        }
    
    }
    
  2. ==============================

    2.방금 추가하여

    방금 추가하여

    SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext (this);

    명시적인 한정자를 추가하려고 할 때도 왜 이렇게해야하는지 확신 할 수 없습니다. 이제 코드는 다음과 같이 보입니다.

    public void doFilter(ServletRequest request, ServletResponse response,
                FilterChain chain) throws IOException, ServletException {
    
            SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
    
            @SuppressWarnings("unchecked")
            Map<String, String[]> parms = request.getParameterMap();
    
            if (parms.containsKey("token")) {
    
  3. ==============================

    3.그것은 충분히 오래된 질문이지만, 나는이 문제를 저에게 좋아하는 사람들을 위해 대답을 추가 할 것입니다.

    그것은 충분히 오래된 질문이지만, 나는이 문제를 저에게 좋아하는 사람들을 위해 대답을 추가 할 것입니다.

    GenericFilterBean에서 필터를 상속 받아 Spring @Component로 표시해야합니다.

    @Component
    public class MyFilter extends GenericFilterBean {
    
        @Autowired
        private MyComponent myComponent;
    
     //implementation
    
    }
    

    그런 다음 Spring 컨텍스트에 등록하십시오.

    @Configuration
    public class MyFilterConfigurerAdapter extends WebMvcConfigurerAdapter {
    
        @Autowired
        private MyFilter myFilter;
    
        @Bean
        public FilterRegistrationBean myFilterRegistrationBean() {
            FilterRegistrationBean regBean = new FilterRegistrationBean();
            regBean.setFilter(myFilter);
            regBean.setOrder(1);
            regBean.addUrlPatterns("/myFilteredURLPattern");
    
            return regBean;
        }
    }
    

    이렇게하면 필터에서 구성 요소가 올바르게 자동 작성됩니다.

  4. ==============================

    4.필터 클래스가 GenericFilterBean을 확장하면 다음과 같이 앱 컨텍스트에서 Bean에 대한 참조를 얻을 수 있습니다.

    필터 클래스가 GenericFilterBean을 확장하면 다음과 같이 앱 컨텍스트에서 Bean에 대한 참조를 얻을 수 있습니다.

    public void initFilterBean() throws ServletException {
    
    @Override
    public void initFilterBean() throws ServletException {
    
            WebApplicationContext webApplicationContext =
                WebApplicationContextUtils.getWebApplicationContext(getServletContext());
            //reference to bean from app context
            yourBeanToInject = webApplicationContext.getBean(yourBeanToInject.class);
    
            //do something with your bean
            propertyValue = yourBeanToInject.getValue("propertyName");
    }
    

    그리고 여기에는 빈 이름을 하드 코딩하지 않거나 하나 이상의 빈 참조를 필터에 삽입해야하는 사람들을위한 덜 분명한 방법이 있습니다.

    @Autowired
    private YourBeanToInject yourBeanToInject;
    
    @Override
    public void initFilterBean() throws ServletException{
    
        SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, getServletContext());
    
        //do something with your bean
        propertyValue = yourBeanToInject.getValue("propertyName");
    }
    
  5. ==============================

    5.빈 필터를 구성하고 필요한 매개 변수로 전달할 수 있습니다. 스프링 컨텍스트가 필터인지, 스프링의 자동 스캔이 의존성 주입을 얻을 수 없는지 알고 있습니다. 하지만 100 % 확실한 주석이 있다면 필터에 넣어서 마법 같은 것들을 할 수는 없습니다.

    빈 필터를 구성하고 필요한 매개 변수로 전달할 수 있습니다. 스프링 컨텍스트가 필터인지, 스프링의 자동 스캔이 의존성 주입을 얻을 수 없는지 알고 있습니다. 하지만 100 % 확실한 주석이 있다면 필터에 넣어서 마법 같은 것들을 할 수는 없습니다.

       <filter>
       <filter-name>YourFilter</filter-name>
           <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        </filter>
    
    <filter-mapping>
       <filter-name>YourFilter</filter-name>
           <url-pattern>/*</url-pattern>
        </filter-mapping>
    

    bean을 spring.xml에 삽입한다.

      <bean id="YourFilter" class="com.YourFilter">
         <property name="param">
            <value>values</value>
         </property>
      </bean>
    
  6. from https://stackoverflow.com/questions/32494398/unable-to-autowire-the-service-inside-my-authentication-filter-in-spring by cc-by-sa and MIT license