2012-07-07 116 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 /> 


你错过键入一些地方,这是我给你纠正。