自定义身份验证提供程序中的自动装配为空

时间:2018-04-18 09:01:39

标签: authentication spring-security nullpointerexception autowired userdetailsservice

我面临一个严重的问题,我无法弄清楚如何解决它。

基本上,在我的自定义身份验证提供程序中,我无法自动装入我的customUserDetailsS​​ervice,它返回一个空指针异常。

我要粘贴我正在使用的所有类加上异常,这里的问题是它自动装配但它返回NULL,它不会在自动装配本身上给我一个错误。

SecurityConfig类:

package esercizio.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    DbAuthenticationProvider dbAuthenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // SecurityContextHolder.getContext().getAuthentication();
        auth.authenticationProvider(new DbAuthenticationProvider());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // .addFilterBefore(
                // new HeaderUsernamePasswordAuthenticationFilter(authenticationManager()),
                // BasicAuthenticationFilter.class)
                .csrf().disable().authorizeRequests().antMatchers("/resources/**").permitAll().antMatchers("/auth/**")
                .hasRole("USER").anyRequest().authenticated().and().formLogin()
                // .loginPage("/login.jsp")
                .loginProcessingUrl("/signin").permitAll().failureForwardUrl("/errorPage")
                .successForwardUrl("/successPage").and().logout().addLogoutHandler(customLogoutHandler())
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"));
        // .and()
        // .exceptionHandling().accessDeniedPage("/403");
    }

    @Bean
    public CustomLogoutHandler customLogoutHandler() {
        return new CustomLogoutHandler();
    }
}

自定义身份验证提供程序:

package esercizio.security;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;

@Component
public class DbAuthenticationProvider implements AuthenticationProvider {
    Logger logger = LogManager.getLogger(this.getClass());

    @Autowired
    UserDetailsService customUserDetailsService;

    public DbAuthenticationProvider() {
        // TODO Auto-generated constructor stub
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String name = authentication.getName();
        Object credentials = authentication.getCredentials();
        List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
        UserDetails user = customUserDetailsService.loadUserByUsername(name);
        Authentication auth = null;

        if (!(credentials instanceof String)) {
            return null;
        }
        String password = null;
        try {
            password = getMD5(credentials.toString());
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        if (user != null && (user.getUsername().equals(name) && user.getPassword().equals(password))) {
            grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
            auth = new UsernamePasswordAuthenticationToken(name, password, grantedAuthorities);
        } else {
            throw new BadCredentialsException("Errore nell'autenticazione");
        }

        return auth;
    }

    @Override
    public boolean supports(Class<?> arg0) {
        return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(arg0));
    }

    public String getMD5(String data) throws NoSuchAlgorithmException {
        MessageDigest messageDigest = MessageDigest.getInstance("MD5");

        messageDigest.update(data.getBytes());
        byte[] digest = messageDigest.digest();
        StringBuffer sb = new StringBuffer();
        for (byte b : digest) {
            sb.append(Integer.toHexString((int) (b & 0xff)));
        }
        return sb.toString();
    }

}

CustomUserDetailsS​​ervice

package esercizio.service;

import org.springframework.beans.factory.annotation.Autowired;
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.Service;

import esercizio.database.dao.UsersDAO;
import esercizio.database.dto.UsersDTO;

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UsersDAO usersDAO;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // TODO Auto-generated method stub
        UsersDTO userTemp = usersDAO.findByUsername(username);

        return userTemp;
    }
}

WEB.XML

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1">
    <servlet>
        <servlet-name>InitServlet</servlet-name>
        <servlet-class>esercizio.InitServlet</servlet-class>
        <load-on-startup>0</load-on-startup>
    </servlet>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/springmvc-servlet.xml
            /WEB-INF/spring-security-context.xml
        </param-value>
    </context-param>

    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>InitServlet</servlet-name>
        <url-pattern>/InitServlet</url-pattern>
    </servlet-mapping>

    <listener>
        <listener-class>esercizio.listener.SessionListener</listener-class>
    </listener>

     <!-- <filter>
        <filter-name>RedirectFilter</filter-name>
        <filter-class>esercizio.filters.RedirectFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>RedirectFilter</filter-name>
        <url-pattern></url-pattern>
    </filter-mapping>  

    <welcome-file-list>
        <welcome-file>login.jsp</welcome-file>
    </welcome-file-list> --> 

    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>

</web-app>

弹簧servlet.xml中

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans     
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd
    http://www.springframework.org/schema/data/jpa
    http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
    http://www.springframework.org/schema/data/mongo
        http://www.springframework.org/schema/data/mongo/spring-mongo-1.2.xsd
        http://www.springframework.org/schema/data/repository
        http://www.springframework.org/schema/data/repository/spring-repository-1.5.xsd">

    <context:component-scan base-package="esercizio" />
    <context:annotation-config />
    <jpa:repositories base-package="esercizio.database.dao" />


    <bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/views/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>

    <bean id="multipartResolver"
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- max upload size in bytes -->
        <property name="maxUploadSize" value="20971520" /> <!-- 20MB -->

        <!-- max size of file in memory (in bytes) -->
        <property name="maxInMemorySize" value="1048576" /> <!-- 1MB -->

    </bean>

    <bean
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations"
            value="classpath:/esercizio/properties/db.properties" />
    </bean>

     <bean id="JDBCDataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close">

        <property name="driverClassName" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean> 

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="JDBCDataSource" />
    </bean>


    <!-- <bean id="tjtJTransactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="JDBCDataSource" />
    </bean> 

    <tx:annotation-driven transaction-manager="tjtJTransactionManager" />-->



    <mvc:resources mapping="/resources/**" location="/resources/theme1/"
        cache-period="31556926" />

    <mvc:annotation-driven />
</beans>

Spring Security xml(它主要用于扫描和激活注释配置)

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    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/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <global-method-security pre-post-annotations="enabled"/>

    <context:annotation-config />

    <context:component-scan base-package="esercizio" />

 </beans:beans>

最后但并非最不重要的是它给我的例外

java.lang.NullPointerException
    esercizio.security.DbAuthenticationProvider.authenticate(DbAuthenticationProvider.java:41)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:174)
    org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:199)
    org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFilter.java:94)
    org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:212)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
    org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
    org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
    org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
    org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
    org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)

如果有人能够弄清楚问题是什么,我将永远感恩,这已经过了3天,我似乎无法解决它。

2 个答案:

答案 0 :(得分:0)

我认为

@Autowired     UserDetailsS​​ervice customUserDetailsS​​ervice;

应该是

@Autowired     CustomUserDetailsS​​ervice customUserDetailsS​​ervice;

答案 1 :(得分:0)

主要原因是,在您configure(AuthenticationManagerBuilder) DbAuthenticationProvider中,您正在构建authentication-manager的新实例,同时将其注入auth.authenticationProvider(new DbAuthenticationProvider());(仅在此行中:Spring-framework)在DbAuthenticationProvider上下文之外,因此注入AuthenticationManager的{​​{1}}实例无法autowire @Autowired UserDetailsService customUserDetailsService

由于此UserDetailsS​​ervice字段为null,因此NullPointerException方法会在authenticate()方法中抛出UserDetails user = customUserDetailsService.loadUserByUsername(name); <{1}}

您可以通过多种方式更改类的加载方式,但最简单的方法是使用此代码块:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    DbAuthenticationProvider dbAuthenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // SecurityContextHolder.getContext().getAuthentication();
        auth.authenticationProvider(new DbAuthenticationProvider());
    }

并改为:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    DbAuthenticationProvider dbAuthenticationProvider;    

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(dbAuthenticationProvider);
    }        

我认为这是更改代码以便开始工作的最简单方法