简体   繁体   English

Spring安全空指针异常

[英]Spring security null pointer exception

I'm trying to map the users in my database to the Spring Security users, but without much luck. 我正在尝试将我的数据库中的用户映射到Spring Security用户,但没有太多运气。 My UserServiceImpl is as follows (the autowiring normally works fine when I'm calling it through a servlet, but throws a null pointer when used in Spring Security... 我的UserServiceImpl如下(当我通过servlet调用它时,自动装配通常工作正常,但在Spring Security中使用时抛出空指针...

@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;
    }
}

I get the following exception (the first line is the System.out) 我得到以下异常(第一行是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)

So it looks like my userDao is not autowiring correctly, but it works fine when I call the service layer from a servlet, just apparently not when using Spring-Security. 所以看起来我的userDao没有正确自动装配,但是当我从servlet调用服务层时它工作正常,显然不是在使用Spring-Security时。

Line 40 refers to return userDao.getByUsername(username); 第40行指的是返回userDao.getByUsername(用户名);

Does anyone have any ideas how I can get the userDao to be populated through @autowired? 有没有人有任何想法如何让userDao通过@autowired填充? As I say, it works fine when I call it through a servlet, just not when trying to use spring-security. 正如我所说,当我通过servlet调用它时它工作正常,而不是在尝试使用spring-security时。

Is there any easier way I can map users and passwords in Spring-security? 有没有更简单的方法可以在Spring-security中映射用户和密码?

My security-app-context is as follows... 我的安全应用程序上下文如下......

<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> 

I guess my question is, why is my userDao @Autowired not working with spring-security, yet it works fine when used in a servlet to return the user object? 我想我的问题是,为什么我的userDao @Autowired不使用spring-security,但是当在servlet中使用它来返回用户对象时它可以正常工作? For example, the following servlet works fine... 例如,以下servlet工作正常......

Why is my autowiring (as it throws a NPE) not working when it's going through spring-security, yet it works fine when being called from a servlet? 为什么我的自动装配(因为它抛出一个NPE)在通过spring-security时不工作,但是从servlet调用时它工作正常?

EDIT :- added 编辑: - 补充说

But now I get 但现在我明白了

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'.

You care creating your service through bean declaration: 您关心通过bean声明创建服务:

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

therefore you need to configure it as eligible for autowiring by setting property autowire . 因此,您需要通过设置属性autowire将其配置为有资格进行自动autowire Default is No . 默认为No The configuration will look like: 配置如下:

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

additionally you could indicate that this bean will participate in others bean autowire process by configuring property autowire-candidate="true". 此外,您可以通过配置属性autowire-candidate =“true”来指示此bean将参与其他bean autowire进程。

Check documentation in order to find out which is the best strategy for your bean have its properties autowired. 检查文档以找出哪个是bean的最佳策略是自动装配其属性。 I personally use byType and constructor , but it depends really on your requirement. 我个人使用byTypeconstructor ,但它实际上取决于您的要求。

Another solution would be configure default-autowire="true" in the tag beans of your context. 另一种解决方案是在上下文的标记beans中配置default-autowire="true"

我想你刚刚错过了spring-security context中的<context:annotation-config/><context:component-scan base-package="..."/>

I just notice that you've double the tag in your xml file. 我只是注意到你的xml文件中的标记加倍了。

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

Let's try removing it. 我们试着删除它。

All you have to do is to replace your security-app-context with this: 您所要做的就是用以下方法替换您的security-app-context:

<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 />


You miss typed some parts, which I corrected for you. 你错过了打字的部分,我为你纠正了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM