Je suis un débutant de printemps et face à des problèmes avec Spring Security. J'essaye d'implémenter un UserDetailsService personnalisé pour l'extraction d'utilisateur et obtenant une exception de pointeur nul quand j'accède à l'objet UserService. Je suis autowiring cet objet. Le autowirng fonctionne bien quand il est fait sur d'autres méthodes de contrôleur et de service mais pour une raison quelconque, il ne fonctionne pas ici et donc j'obtiens l'exception de pointeur nul quand l'objet autowired (UserService) est accédé.Spring Security 3.1 + JPA - Exception pointeur nul
J'apprécierais vraiment l'aide à ce sujet.
Exception Trace de la pile:
java.lang.NullPointerException
java.lang.NullPointerException
at com.contact.list.service.CustomUserDetailsService.loadUserByUsername(CustomUserDetailsService.java:37)
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:81)
at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:132)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:194)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:323)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:173)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at com.springsource.insight.collection.tcserver.request.HttpRequestOperationCollectionValve.invoke(HttpRequestOperationCollectionValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1001)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
CustomUserDetailsService Classe:
package com.contact.list.service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.contact.list.form.Role;
import com.contact.list.repository.UserRepository;
@Service
@Transactional(readOnly = true)
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserService userService;
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
try{
com.contact.list.form.User domainuser = userService.findByUsername(username);
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
return new User(domainuser.getUsername(),
domainuser.getPassword().toLowerCase(),
enabled,accountNonExpired,
credentialsNonExpired,
accountNonLocked,
getAuthorities(domainuser.getRoles())
);
}catch (Exception e){
System.out.println(e);
e.printStackTrace();
throw new RuntimeException(e);
}
}
public Collection<? extends GrantedAuthority> getAuthorities(List<Role> roles){
List<GrantedAuthority> authList = getGrantedAuthorities(getroles(roles));
return authList;
}
public static List<GrantedAuthority> getGrantedAuthorities(List<String> userroles){
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for(String userrole:userroles){
authorities.add(new SimpleGrantedAuthority(userrole));
}
return authorities;
}
public List<String> getroles(List<Role> roles){
List<String> userroles = new ArrayList<String>();
for (Role role : roles){
if(role.getRole() == 1){
userroles.add("ROLE_USER");
}
if(role.getRole() == 2){
userroles.add("ROLE_ADMIN");
}
}
return userroles;
}
}
UserService Interface:
package com.contact.list.service;
import java.util.List;
import com.contact.list.form.Contact;
import com.contact.list.form.User;
public interface UserService {
public List<User> findAll();
public void save(User user);
public User findByUsername(String username);
}
UserService classe de mise en œuvre:
package com.contact.list.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.contact.list.form.Contact;
import com.contact.list.form.User;
import com.contact.list.repository.UserRepository;
import com.google.common.collect.Lists;
@Service
@Repository
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userrepository;
public void save(User user) {
userrepository.save(user);
}
@Transactional(readOnly=true)
public List<User> findAll() {
return Lists.newArrayList(userrepository.findAll());
}
public User findByUsername(String username){
return userrepository.findByUsername(username);
}
}
Userrepository:
package com.contact.list.repository;
import org.springframework.data.repository.CrudRepository;
import com.contact.list.form.User;
public interface UserRepository extends CrudRepository<User, Long> {
User findByUsername(String username);
}
Classe utilisateur:
package com.contact.list.form;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "USER_TBL")
public class User {
@Column(name = "FIRST_NAME")
private String firstName;
@Column(name = "LAST_NAME")
private String lastName;
@Column(name = "EMAIL")
private String email;
@Id
@Column(name = "USERID")
private String username;
@Column(name = "PASSWORD")
private String password;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Role> roles = new ArrayList<Role>();
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
}
web.xml:
<!-- Spring Security Configuration -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/root-context.xml
/WEB-INF/spring-security.xml
</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/appServlet/servlet-context.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
servlet-context.xml:
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC @Controller programming model -->
<annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<interceptors>
<beans:bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
</interceptors>
<beans:bean id="themeSource" class="org.springframework.ui.context.support.ResourceBundleThemeSource"/>
<beans:bean id="themeResolver" class="org.springframework.web.servlet.theme.CookieThemeResolver"/>
<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="/WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
<beans:property name="requestContextAttribute" value="requestContext"/>
</beans:bean>
<context:component-scan base-package="com.contact.list" />
<beans:bean id = "myDataSource" class = "org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<beans:property name="driverClassName" value = "org.postgresql.Driver"/>
<beans:property name="url" value = "jdbc:postgresql://localhost:5432/hibernatedb"/>
<beans:property name="username" value = "postgres"/>
<beans:property name="password" value = "password"/>
</beans:bean>
<!-- JPA Config -->
<beans:bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<beans:property name="entityManagerFactory" ref="emf"/>
</beans:bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<beans:bean id = "emf" class = "org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<beans:property name = "dataSource" ref = "myDataSource"/>
<beans:property name = "jpaVendorAdapter">
<beans:bean class = "org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</beans:property>
<beans:property name = "packagesToScan" value = "com.contact.list.form" />
<beans:property name="jpaProperties">
<beans:props>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</beans:prop>
<beans:prop key = "hibernate.show_sql">true</beans:prop>
<beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<beans:bean id = "passwordEncoder" class = "org.springframework.security.authentication.encoding.Md5PasswordEncoder"/>
<context:annotation-config/>
<!-- JPA Config -->
<!-- JPA Repository Abstraction Config -->
<jpa:repositories base-package="com.contact.list.repository" entity-manager-factory-ref="emf" transaction-manager-ref="transactionManager"/>
printemps-security.xml
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/home*" access="hasRole('ROLE_USER')"/>
<form-login login-page="/login" default-target-url="/home" authentication-failure-url="/loginfailed" />
<logout logout-success-url="/logout" />
</http>
<authentication-manager>
<authentication-provider user-service-ref = "customUserDetailsService">
<password-encoder ref = "passwordEncoder"/>
</authentication-provider>
</authentication-manager>
<beans:bean id="customUserDetailsService" class="com.contact.list.service.CustomUserDetailsService"/>
<beans:bean id = "passwordEncoder" class = "org.springframework.security.authentication.encoding.Md5PasswordEncoder"/>
</beans:beans>
est '@ Autowired' travaille dans toute autre partie de votre demande? Avez-vous ' ' ou ' ' dans votre XML? –
Peut-être votre bean "UserService" est défini dans un enfant ApplicationContext (servlet-context.xml) et spring-security.xml est chargé dans un parent ApplicationContext (contexte racine, chargé par ContextLoaderListener) – Luciano
@Tomasz Nurkiewicz: Oui Autowire fonctionne dans d'autres parties de l'application. Et j'ai ce qui suit dans mon xml: -> Tous les paquets sont à l'intérieur. Et oui, j'ai aussi dans mon xml. –