web-dev-qa-db-ja.com

Springの認証フィルター内でサービスを自動配線できません

私はトークンでユーザーを認証しようとしていますが、サービスをAuthenticationTokenProcessingFilter内に自動接続しようとすると、nullポインタ例外が発生します。 自動配線されたサービスが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);
    }
}

AppConfigに以下を追加してみました

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

私のAppConfigアノテーションは

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

私はちょうど追加してそれを動作させました

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")) {
18
Raghu Chandra

すぐに使用できるフィルターからの依存性注入は使用できません。 GenericFilterBeanを使用していますが、Servlet Filterはspringによって管理されていません。 javadocsに記載されているとおり

この汎用フィルター基本クラスは、Spring org.springframework.context.ApplicationContextコンセプトに依存しません。通常、フィルターは独自のコンテキストを読み込まず、フィルターのServletContextを介してアクセス可能なSpringルートアプリケーションコンテキストからサービスBeanにアクセスします(org.springframework.web.context.support.WebApplicationContextUtilsを参照)。

平易な英語では、春がサービスを注入することを期待することはできませんが、最初の呼び出しで遅延設定することができます。例えば。

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 ...    
    }

}
41
Haim Raman

これは十分に古い質問ですが、この問題をGoogleで検索するのが好きな人には答えを追加します。

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;
    }
}

これにより、フィルター内のコンポーネントが適切に自動配線されます。

16
Yuriy Kovalek

フィルタークラスが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");
}

また、Bean名をハードコーディングするのが嫌いな人や、複数のBean参照をフィルターに挿入する必要がある人のための、あまり明確でない方法を次に示します。

@Autowired
private YourBeanToInject yourBeanToInject;

@Override
public void initFilterBean() throws ServletException{

    SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, getServletContext());

    //do something with your bean
    propertyValue = yourBeanToInject.getValue("propertyName");
}
3
Igor Vash

Beanフィルターを構成し、パラメーターとして必要なものを渡すことができます。私はSpringのコンテキストからフィルターがどこにあるかを知っていますが、springの自動スキャンが行う依存性注入を取得することはできません。しかし、いくつかの魔法のようなことをするためにあなたのフィルターに入れることができる凝ったアノテーションがあるかどうか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>

そして、spring.xmlにBeanを注入します

  <bean id="YourFilter" class="com.YourFilter">
     <property name="param">
        <value>values</value>
     </property>
  </bean>
1
paul

私はパーティーに遅れましたが、この解決策はうまくいきました。

Web.xmlにContextLoaderListenerを追加します。 applicationContextは依存関係Beanを持つことができます。

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>

次に、MyFilter SpringBeanAutowiringSupport processInjectionBasedOnServletContextを追加します。これにより、webapplicationcontextがフィルターに追加され、すべての依存関係が追加されます。

@Component
public class MyFilter implements Filter {

    @Autowired
    @Qualifier("userSessionServiceImpl")
    private UserSessionService userSessionServiceImpl;

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain 
    chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) req;
        if (userSessionServiceImpl == null) {
            ServletContext context = httpRequest.getSession().getServletContext();
        SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, context);
    }

       .... (for brevity)
    }

}

0
user9059436