Не удалось отключить службу внутри фильтра проверки подлинности в Spring
Я пытаюсь выполнить аутентификацию пользователя с помощью токена, но когда я пытаюсь автопроверить одну из моих служб внутри AuthenticationTokenProcessingFilter
, я получаю исключение из null-указателя. , потому что функция autwired имеет значение 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);
}
}
Я пробовал добавить follwing в мой AppConfig
@Bean(name="myServices")
public MyServices stockService() {
return new MyServiceImpl();
}
Мои аннотации AppConfig
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.marketplace")
public class AppConfig extends WebMvcConfigurerAdapter {
Ответы
Ответ 1
Я просто сделал это, добавив
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(это);
Я не уверен, почему мы должны это делать, даже когда я пытался добавить явный квалификатор. и теперь код выглядит как
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")) {
Ответ 2
Вы не можете использовать инъекцию зависимостей из фильтра из коробки. Хотя вы используете GenericFilterBean, ваш сервлет-фильтр не управляется spring. Как отмечено javadocs
Этот общий базовый класс фильтра не зависит от Springorg.springframework.context.ApplicationContext. фильтры обычно не загружают свой собственный контекст, а получают доступ к сервису beansиз контекста корневого приложения Spring, доступного через фильтр ServletContext (см. org.springframework.web.context.support.WebApplicationContextUtils).
На простом английском языке мы не можем ожидать 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 ...
}
}
Ответ 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
Вы можете настроить фильтр 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>
а затем введите bean в spring.xml
<bean id="YourFilter" class="com.YourFilter">
<property name="param">
<value>values</value>
</property>
</bean>
Ответ 5
Если ваш класс фильтра расширяет 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");
}
И здесь менее явный способ для тех, кому не нравятся имена hardcoding 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");
}