Java 无法在 Spring 的身份验证过滤器中自动装配服务
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32494398/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Unable to autowire the service inside my authentication filter in Spring
提问by Raghu Chandra
I am trying to authenticate user by token, But when i try to auto wire one my services inside the AuthenticationTokenProcessingFilter
i get null pointer exception. because autowired service is null, how can i fix this issue ?
我正在尝试通过令牌对用户进行身份验证,但是当我尝试在其中自动连接我的服务时,AuthenticationTokenProcessingFilter
我得到了空指针异常。因为自动装配服务为空,我该如何解决这个问题?
My AuthenticationTokenProcessingFilter
class
我的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);
}
}
I Tried adding follwing in my AppConfig
我尝试在我的 AppConfig
@Bean(name="myServices")
public MyServices stockService() {
return new MyServiceImpl();
}
My AppConfig Annotations are
我的 AppConfig 注释是
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.marketplace")
public class AppConfig extends WebMvcConfigurerAdapter {
采纳答案by Raghu Chandra
I just made it work by adding
我只是通过添加使其工作
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
I am unsure why we should do this even when i tried adding explicit qualifier. and now the code looks like
即使我尝试添加显式限定符,我也不确定为什么我们应该这样做。现在代码看起来像
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")) {
回答by paul
You can configure your bean filter and pass as a parameter whatever you need. I know out of Spring context where the filter it is, you cannot get the dependency injection that the auto-scan of spring does. But not 100% sure if there′s a fancy annotation that you can put in your filter to do some magic stuff
您可以配置 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>
and then inject bean in the spring.xml
然后在spring.xml中注入bean
<bean id="YourFilter" class="com.YourFilter">
<property name="param">
<value>values</value>
</property>
</bean>
回答by Haim Raman
You cannot use dependency injection from a filter out of the box. Although you are using GenericFilterBean your Servlet Filter is not managed by spring. As noted by the javadocs
您不能使用开箱即用的过滤器中的依赖注入。尽管您使用的是 GenericFilterBean,但您的 Servlet 过滤器不是由 spring 管理的。正如javadocs所指出的
This generic filter base class has no dependency on the Spring org.springframework.context.ApplicationContext concept. Filters usually don't load their own context but rather access service beans from the Spring root application context, accessible via the filter's ServletContext (see org.springframework.web.context.support.WebApplicationContextUtils).
这个通用过滤器基类不依赖于 Spring org.springframework.context.ApplicationContext 概念。过滤器通常不加载自己的上下文,而是从 Spring 根应用程序上下文访问服务 bean,可通过过滤器的 ServletContext 访问(请参阅 org.springframework.web.context.support.WebApplicationContextUtils)。
In plain English we cannot expect spring to inject the service, but we can lazy set it on the first call. E.g.
用简单的英语,我们不能指望 spring 注入服务,但我们可以在第一次调用时延迟设置它。例如
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 ...
}
}
回答by Yuriy Kovalek
It's an old enough question, but I'll add my answer for those who like me google this issue.
这是一个足够古老的问题,但我会为喜欢我的人添加我的答案谷歌这个问题。
You must inherit your filter from GenericFilterBean
and mark it as a Spring @Component
您必须继承过滤器GenericFilterBean
并将其标记为 Spring@Component
@Component
public class MyFilter extends GenericFilterBean {
@Autowired
private MyComponent myComponent;
//implementation
}
And then register it in Spring context:
然后在 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;
}
}
This properly autowires your components in the filter.
这会正确地在过滤器中自动装配您的组件。
回答by Igor Vash
If your filter class extends GenericFilterBean you can get a reference to a bean in your app context this way:
如果您的过滤器类扩展了 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");
}
And here is less explicit way for those who doesn't like hardcoding bean names or need to inject more than one bean reference into the filter:
对于那些不喜欢硬编码 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");
}
回答by user9059436
I am late to the party but this solution worked for me.
我参加聚会迟到了,但这个解决方案对我有用。
Add a ContextLoaderListener in web.xml. applicationContext can have dependency beans.
在 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>
Then add in MyFilter SpringBeanAutowiringSupport processInjectionBasedOnServletContext which will add the webapplicationcontext into the filter which will add all the dependencies.
然后添加 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)
}
}
}