2012-07-07 133 views
7

我試圖將我的數據庫中的用戶映射到Spring Security用戶,但沒有多少運氣。我UserServiceImpl如下(自動裝配正常工作時,我稱它通過servlet罰款,但在春季安全使用時拋出一個空指針...彈簧安全性空指針異常

@Service("userService") 
@Transactional 
public class UserServiceImpl implements UserService, UserDetailsService { 

    protected static Logger logger = Logger.getLogger("service"); 

    @Autowired 
    private UserDAO userDao; 

    public UserServiceImpl() { 
    } 

    @Transactional 
    public User getById(Long id) { 
     return userDao.getById(id); 
    } 

    @Transactional 
    public User getByUsername(String username) { 
     return userDao.getByUsername(username); 
    } 

    @Override 
    public UserDetails loadUserByUsername(String username) 
      throws UsernameNotFoundException { 

     UserDetails user = null; 
     try { 
      System.out.println(username); 
      User dbUser = getByUsername(username); 

      user = new org.springframework.security.core.userdetails.User(
        dbUser.getUsername(), dbUser.getPassword(), true, true, 
        true, true, getAuthorities(dbUser.getAccess())); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      logger.log(Level.FINE, "Error in retrieving user"); 
      throw new UsernameNotFoundException("Error in retrieving user"); 
     } 

     // Return user to Spring for processing. 
     // Take note we're not the one evaluating whether this user is 
     // authenticated or valid 
     // We just merely retrieve a user that matches the specified username 
     return user; 
    } 

    public Collection<GrantedAuthority> getAuthorities(Integer access) { 
     // Create a list of grants for this user 
     List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(2); 

     // All users are granted with ROLE_USER access 
     // Therefore this user gets a ROLE_USER by default 
     logger.log(Level.INFO, "User role selected"); 
     authList.add(new GrantedAuthorityImpl("ROLE_USER")); 

     // Check if this user has admin access 
     // We interpret Integer(1) as an admin user 
     if (access.compareTo(1) == 0) { 
      // User has admin access 
      logger.log(Level.INFO, "Admin role selected"); 
      authList.add(new GrantedAuthorityImpl("ROLE_ADMIN")); 
     } 

     // Return list of granted authorities 
     return authList; 
    } 
} 

我得到下面的異常(第一行是的System.out)

dusername 
java.lang.NullPointerException 
    at org.assessme.com.service.UserServiceImpl.getByUsername(UserServiceImpl.java:40) 
    at org.assessme.com.service.UserServiceImpl.loadUserByUsername(UserServiceImpl.java:50) 
    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:235) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) 
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) 
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) 
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) 
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) 
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) 
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298) 
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859) 
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588) 
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489) 
    at java.lang.Thread.run(Thread.java:722) 

因此,它看起來像我userDAO的不正確自動裝配,但是當我從一個servlet調用服務層,使用Spring-Security時只是顯然不是它工作正常。

第40行指向返回userDao.getByUsername(usern AME);

有沒有人有任何想法我可以讓userDao通過@autowired填充?正如我所說的,當我通過一個servlet調用它的時候它工作正常,而不是在嘗試使用spring-security時。

有沒有更簡單的方法可以映射Spring-security中的用戶和密碼?

我的安全應用程序上下文如下:...

<beans:beans xmlns="http://www.springframework.org/schema/security" 
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
        http://www.springframework.org/schema/security 
        http://www.springframework.org/schema/security/spring-security-3.1.xsd" 
        xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"> 
<context:annotation-config /> 
<context:component-scan base-package="org.assessme.com." /> 


    <http pattern="/static/**" security="none" /> 
    <http use-expressions="true"> 
     <intercept-url pattern="/login" access="permitAll" /> 
     <intercept-url pattern="/*" access="isAuthenticated()" /> 
     <!-- <intercept-url pattern="/secure/extreme/**" access="hasRole('supervisor')" 
      /> --> 
     <!-- <intercept-url pattern="/listAccounts.html" access="isAuthenticated()" 
      /> --> 
     <!-- <intercept-url pattern="/post.html" access="hasAnyRole('supervisor','teller')" 
      /> --> 
<!--  <intercept-url pattern="/*" access="denyAll" /> --> 
     <form-login /> 
     <logout invalidate-session="true" logout-success-url="/" 
      logout-url="/logout" /> 
    </http> 

    <authentication-manager> 
     <authentication-provider user-service-ref="UserDetailsService"> 
      <password-encoder ref="passwordEncoder"/> 
     </authentication-provider> 
</authentication-manager> 
<context:component-scan base-package="org.assessme.com" /><context:annotation-config /> 
<beans:bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" id="passwordEncoder"/> 

<beans:bean class="org.assessme.com.service.UserServiceImpl" id="UserDetailsService" autowire="byType"/> 


</beans:beans> 

我想我的問題是,爲什麼是我userDAO的@Autowired不帶彈簧的安全工作,但在使用時,它工作正常servlet返回用戶對象?例如,以下servlet可以正常工作...

爲什麼我的自動裝配(因爲它引發NPE)在它正在經歷spring-security時無法正常工作,但是從servlet調用它時工作正常嗎?

編輯: - 增加

但現在我得到

ERROR: org.springframework.web.context.ContextLoader - Context initialization failed 
org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 9 in XML document from ServletContext resource [/WEB-INF/spring/security-app-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 9; columnNumber: 30; cvc-complex-type.2.4.c: The matching wildcard is strict, but no declaration can be found for element 'context:annotation-config'. 

回答

8

你關心創建通過bean聲明爲您服務:

<beans:bean class="org.assessme.com.service.UserServiceImpl" id="UserDetailsService"/> 

因此,你需要將其配置爲符合自動裝配通過設置屬性autowire。默認是No。配置將是這樣的:

<beans:bean class="org.assessme.com.service.UserServiceImpl" id="UserDetailsService" autowire="byType" /> 

另外你說明這個bean將通過配置屬性自動裝配候選=「真正的」參與人豆自動裝配過程。

檢查documentation爲了找出哪些是你的bean的最佳策略,它的屬性是自動裝配的。我個人使用byTypeconstructor,但這取決於您的要求。

另一種解決方案是在您的上下文的標籤beans中配置default-autowire="true"

+0

我添加了但是在重新啓動Tomcat後,我仍然在同一行上得到一個NPE。更新的問題,但謝謝你的建議:) – david99world 2012-07-07 12:45:34

+0

請你可以添加到你的上下文xml:' ' – 2012-07-07 12:50:04

+0

另外,我已經有\t 在我的servlet上下文中,我是否需要在兩個XML文件中? – david99world 2012-07-07 12:56:25

2

我想你錯過了彈簧安全上下文中的<context:annotation-config/><context:component-scan base-package="..."/>

+0

這給出了錯誤:org.springframework.web.context.ContextLoader - 上下文初始化失敗...用新的xml更新了問題,感謝您的幫助:) – david99world 2012-07-07 12:59:15

+0

您當然需要在XML開頭聲明XML上下文名稱空間文件,如http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#beans-annotation-config – 2012-07-07 13:03:43

+0

中所示啊,我想我是否用xmlns:context =「http://www.springframework.org/schema/context」xmlns:tx =「http://www.springframework.org/schema/tx」 – david99world 2012-07-07 13:04:43

0

我只是注意到你已經在你的xml文件中加了兩倍的標籤。

<context:component-scan base-package="org.assessme.com" /><context:annotation-config /> 

讓我們嘗試刪除它。

0

所有你需要做的就是用它來取代您的安全應用程序上下文:

<beans:beans xmlns="http://www.springframework.org/schema/security" 
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
       http://www.springframework.org/schema/security 
       http://www.springframework.org/schema/security/spring-security-3.1.xsd" 
       xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"> 

<context:annotation-config> 
<context:component-scan base-package="org.assessme.com." /> 

<http pattern="/static/**" security="none" /> 
<http use-expressions="true"> 
    <intercept-url pattern="/login" access="permitAll" /> 
    <intercept-url pattern="/*" access="isAuthenticated()" /> 
    <!-- <intercept-url pattern="/secure/extreme/**" access="hasRole('supervisor')" 
     /> --> 
    <!-- <intercept-url pattern="/listAccounts.html" access="isAuthenticated()" 
     /> --> 
    <!-- <intercept-url pattern="/post.html"  access="hasAnyRole('supervisor','teller')" 
     /> --> 
<!--  <intercept-url pattern="/*" access="denyAll" /> --> 
    <form-login /> 
    <logout invalidate-session="true" logout-success-url="/" 
     logout-url="/logout" /> 
</http> 
<authentication-manager> 
    <authentication-provider user-service-ref="UserDetailsService"> 
     <password-encoder ref="passwordEncoder"/> 
    </authentication-provider> 
</authentication-manager> 
<context:annotation-config /> 


你錯過鍵入一些地方,這是我給你糾正。