J'essaie d'authentifier l'utilisateur par jeton, mais lorsque j'essaie de câbler automatiquement mes services à l'intérieur de AuthenticationTokenProcessingFilter
, j'obtiens une exception de pointeur nul. car le service câblé automatiquement est nul, comment puis-je résoudre ce problème?
Ma classe 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);
}
}
J'ai essayé d'ajouter follwing dans mon AppConfig
@Bean(name="myServices")
public MyServices stockService() {
return new MyServiceImpl();
}
Mes annotations AppConfig sont
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.marketplace")
public class AppConfig extends WebMvcConfigurerAdapter {
Je viens de le faire fonctionner en ajoutant
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext (this);
Je ne sais pas pourquoi nous devrions le faire même lorsque j'ai essayé d'ajouter un qualificatif explicite. et maintenant le code ressemble
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")) {
Vous ne pouvez pas utiliser l'injection de dépendance à partir d'un filtre prêt à l'emploi. Bien que vous utilisiez GenericFilterBean, votre filtre de servlet n'est pas géré au printemps. Comme l'ont noté les javadocs
Cette classe de base de filtre générique ne dépend pas du concept Spring org.springframework.context.ApplicationContext. Les filtres ne chargent généralement pas leur propre contexte mais accèdent plutôt aux beans de service à partir du contexte de l'application racine Spring, accessible via le ServletContext du filtre (voir org.springframework.web.context.support.WebApplicationContextUtils).
En clair, nous ne pouvons pas nous attendre à ce que le printemps injecte le service, mais nous pouvons paresseusement le régler au premier appel. Par exemple.
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 ...
}
}
C'est une question assez ancienne, mais je vais ajouter ma réponse pour ceux qui m'aiment google ce problème.
Vous devez hériter votre filtre de GenericFilterBean
et le marquer comme Spring @Component
@Component
public class MyFilter extends GenericFilterBean {
@Autowired
private MyComponent myComponent;
//implementation
}
Et puis enregistrez-le dans le contexte de 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;
}
}
Cela permet de câbler correctement vos composants dans le filtre.
Si votre classe de filtre étend GenericFilterBean, vous pouvez obtenir une référence à un bean dans le contexte de votre application de cette façon:
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");
}
Et voici un moyen moins explicite pour ceux qui n'aiment pas le codage en dur des noms de bean ou qui ont besoin d'injecter plus d'une référence de bean dans le filtre:
@Autowired
private YourBeanToInject yourBeanToInject;
@Override
public void initFilterBean() throws ServletException{
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, getServletContext());
//do something with your bean
propertyValue = yourBeanToInject.getValue("propertyName");
}
Vous pouvez configurer votre filtre bean et passer en paramètre tout ce dont vous avez besoin. Je sais que dans le contexte de Spring où se trouve le filtre, vous ne pouvez pas obtenir l'injection de dépendance que fait l'auto-scan de Spring. Mais je ne suis pas sûr à 100% s'il y a une annotation de fantaisie que vous pouvez mettre dans votre filtre pour faire des trucs magiques
<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>
puis injectez le haricot au printemps.xml
<bean id="YourFilter" class="com.YourFilter">
<property name="param">
<value>values</value>
</property>
</bean>
Je suis en retard à la fête mais cette solution a fonctionné pour moi.
Ajoutez un ContextLoaderListener dans web.xml. applicationContext peut avoir des beans de dépendance.
<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>
Ajoutez ensuite MyFilter SpringBeanAutowiringSupport processInjectionBasedOnServletContext qui ajoutera le webapplicationcontext dans le filtre qui ajoutera toutes les dépendances.
@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)
}
}