java - 未调用 Spring Security Authentication UserDetailsS​​ervice 实现类

标签 java spring hibernate spring-security spring-java-config

我正在尝试从基于 Spring XML 的配置迁移到纯 Java 配置,我已经配置了所有配置文件,但是当我尝试在登录页面中输入用户名和密码时,它再次将我重定向回登录页面.我相信 userServiceImpl 方法没有被调用,因为控件不在那里。 在这里,我有 Autowiring 的 userServiceImpl 方法,它正在实现 Spring Security 核心凭证的 UserDetailsS​​ervice。

package com.lw.sms.config;

import java.util.Properties;

import javax.sql.DataSource;

import org.apache.commons.dbcp.BasicDataSource;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.orm.hibernate4.LocalSessionFactoryBuilder;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import com.lw.sms.CustomAuthenticationSuccessHandler;
import com.lw.sms.UserServiceImpl;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@EnableTransactionManagement
@Order(1000)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);

    @Value("${jdbc.dialect}")
    String jdbcDialect;

    @Value("${jdbc.driverClassName}")
    String jdbcDriverClassName;

    @Value("${jdbc.databaseurl}")
    String jdbcDatabaseurl;

    @Value("${jdbc.username}")
    String jdbcusername;

    @Value("${jdbc.password}")
    String jdbcPassword;

    @Autowired
    private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;

    @Autowired
    private UserServiceImpl userServiceImpl;


    @Override
    public void configure(final AuthenticationManagerBuilder auth) throws Exception {
        logger.info("configure auth");
        auth.userDetailsService(userServiceImpl);
    }


    @Bean
    public PasswordEncoder passwordEncoder() {
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        return encoder;
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        logger.info("configure http");
        http.httpBasic().disable();

        http.authorizeRequests().and().formLogin().loginPage("/login").usernameParameter("employeeId")
                .passwordParameter("password").successHandler(customAuthenticationSuccessHandler)
                .failureUrl("/login?error").defaultSuccessUrl("/dashboard", true)

                .loginProcessingUrl("j_spring_security_check")

                .and().logout().logoutUrl("/j_spring_security_logout").logoutSuccessUrl("/logout")
                .invalidateHttpSession(true).deleteCookies("JSESSIONID")

                .and().sessionManagement().invalidSessionUrl("/logout").maximumSessions(1)
                .maxSessionsPreventsLogin(true).expiredUrl("/logout");
        http.csrf().disable();

        http.authorizeRequests().anyRequest().authenticated();

    }

    @Bean
    public SessionRegistry sessionRegistry() {
        logger.info("sessionRegistry");
        return new SessionRegistryImpl();
    }

    @Bean
    public SessionFactory sessionFactory() {
        LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(dataSource());
        builder.scanPackages("com.lw.sms").addProperties(hibernateProperties());
        return builder.buildSessionFactory();
    }

    @Bean
    public LocalSessionFactoryBean hibernateSessionFactory() {
        logger.info("sessionFactory");
        org.hibernate.cfg.Configuration configuration = new org.hibernate.cfg.Configuration();
        configuration.configure("hibernate.cfg.xml");

        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        sessionFactory.setPackagesToScan("com.lw.sms");
        sessionFactory.setHibernateProperties(hibernateProperties());
        return sessionFactory;
    }

    @Bean
    public DataSource dataSource() {
        logger.info("dataSource");
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setDriverClassName(jdbcDriverClassName);
        dataSource.setUrl(jdbcDatabaseurl);
        dataSource.setUsername(jdbcusername);
        dataSource.setPassword(jdbcPassword);
        return dataSource;
    }

    @Bean
    @Autowired
    public HibernateTransactionManager transactionManager(SessionFactory sessionFactory) {
        logger.info("transactionManager");
        HibernateTransactionManager htm = new HibernateTransactionManager();
        htm.setSessionFactory(sessionFactory);
        return htm;
    }

    @Bean
    public Properties hibernateProperties() {
        logger.info("hibernateProperties");
        Properties hibernateProperties = new Properties();
        hibernateProperties.setProperty("hibernate.show_sql", "true");
        hibernateProperties.setProperty("hibernate.dialect", jdbcDialect);
        hibernateProperties.setProperty("hibernate.default_schema", "sms");
        return hibernateProperties;
    }

}

CustomAuthenticationSuccessHandler代码附在下方

package com.lw.sms;

import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.stereotype.Component;

import com.lw.sms.constants.Constants;
import com.lw.sms.user.entities.EmployeeEntity;
import com.lw.sms.user.entities.EmployeePermissionsEntity;
import com.lw.sms.user.service.UserManagementService;
import com.lw.sms.util.QueryBuilder;


@Component("customAuthenticationSuccessHandler")
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    private static final Logger logger = LoggerFactory.getLogger(CustomAuthenticationSuccessHandler.class);

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();

    @Autowired
    @Qualifier("sessionInfo")
    private SessionInfo sessionInfo;

    @Autowired
    @Qualifier("userManagementServiceImpl")
    private UserManagementService userManagementService;

    @Autowired
    private HttpServletRequest httpServletRequest;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException {
        response.setStatus(HttpServletResponse.SC_OK);
        clearAuthenticationAttributes(request);
        handle(request, response);
    }

    protected void handle(HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

            if (principal instanceof UserDetails) {
                EmployeeEntity employeeEntity = (EmployeeEntity) principal;
                setSessionInformationForEmployee(employeeEntity);
            }

        if (response.isCommitted()) {
            return;
        }
        startServices();
        redirectStrategy.sendRedirect(request, response, "/dashboard");
    }

    /**
     * @param employeeEntity 
     * 
     */
    private void setSessionInformationForEmployee(EmployeeEntity employeeEntity) {
        try {
            WebAuthenticationDetails details = (WebAuthenticationDetails) SecurityContextHolder.getContext()
                    .getAuthentication().getDetails();
            userManagementService.updateLoginInfo(employeeEntity.getUsername(), details.getRemoteAddress());
            // setting session information
        } catch (Exception e) {
            logger.info("Exception while set Session Information For Employee :" + ExceptionUtils.getFullStackTrace(e));
        }
    }

    private void startServices() {
        logger.info("Starting Services..");
        try {
            String domainName = httpServletRequest.getScheme() + "://" + httpServletRequest.getServerName();
            if (httpServletRequest.getServerPort() != 0) {
                domainName += ":" + httpServletRequest.getServerPort();
            }
            domainName += httpServletRequest.getContextPath();
            Constants.domainName = domainName + "/resources";
        } catch (Exception e) {
            logger.error("Error in start services :"+ ExceptionUtils.getFullStackTrace(e));
        }

    }

    protected void clearAuthenticationAttributes(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) {
            return;
        }
        session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
    }

    public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
        this.redirectStrategy = redirectStrategy;
    }

    protected RedirectStrategy getRedirectStrategy() {
        return redirectStrategy;
    }
}

下面附上UserServiceImpl代码

package com.lw.sms;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
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 org.springframework.transaction.annotation.Transactional;

import com.lw.sms.user.dao.UserManagementDAO;
import com.lw.sms.user.entities.EmployeeEntity;

@Service("userServiceImpl")
public class UserServiceImpl implements UserDetailsService {

    @Autowired
    @Qualifier("userManagementDAOImpl")
    private UserManagementDAO userManagementDAO;

    @Override
    @Transactional
    public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
        EmployeeEntity employeeEntity = userManagementDAO.loadUserByUsername(username);
        if (employeeEntity == null) {
            ContractorEntity contractorEntity = userManagementDAO.loadUserByUsernameContractor(username);
            if(contractorEntity == null)
                throw new AuthenticationCredentialsNotFoundException("Invalid Username or Password");
        }
        if(!employeeEntity.isEnabled())
            throw new AuthenticationCredentialsNotFoundException("Employee Disabled");
        return employeeEntity;
    }

}

全局异常处理程序代码:

package com.lw.sms;

import java.io.IOException;
import java.nio.charset.Charset;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.json.simple.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.stereotype.Controller;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.HttpSessionRequiredException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException;

@SuppressWarnings("deprecation")
@Controller
@ControllerAdvice
public class CustomExceptionHandler extends RuntimeException {

    /**
     * 
     */
    private static final long serialVersionUID = 3699167829164697594L;


    private static final Logger logger = LoggerFactory
            .getLogger(CustomExceptionHandler.class);

    @ExceptionHandler(AuthenticationCredentialsNotFoundException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public ModelAndView handleLoginExceptions(HttpServletRequest request,
            HttpServletResponse response,Exception exception) {
        logger.info("Handling exception time error"+ exception.getMessage());
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("login");
        return modelAndView;
    }

    @ExceptionHandler(HttpSessionRequiredException.class)
    public String handleSessionExpired() {
        logger.info("session-expired");
        return "logout";
    }

    @SuppressWarnings("unchecked")
    @ExceptionHandler(value = { MissingServletRequestParameterException.class,
            ServletRequestBindingException.class, TypeMismatchException.class,
            HttpMessageNotReadableException.class,
            MethodArgumentNotValidException.class,
            MissingServletRequestPartException.class })
    @ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "Bad Request")
    @ResponseBody
    public JSONObject handle400Exception(Exception ex,HttpServletResponse response) {
        logger.error("400 Exception" + ex.getMessage());
        JSONObject jsonObject=new JSONObject();
        jsonObject.put("status", HttpStatus.BAD_REQUEST);
        jsonObject.put("success", false);
        jsonObject.put("message", ex.getMessage());
        try {
            response.getOutputStream().write(jsonObject.toString().getBytes(Charset.defaultCharset()));
        } catch (IOException e) {
            logger.error(ExceptionUtils.getFullStackTrace(e));
        }
        response.setContentType("application/json; charset=UTF-8");
        return jsonObject;
    }

    @ExceptionHandler(value = { NoSuchRequestHandlingMethodException.class, })
    @ResponseStatus(value = HttpStatus.NOT_FOUND, reason = "Not Found")
    @ResponseBody
    public Boolean handle404Exception(Exception ex) {
        logger.error("404 Exception" + ExceptionUtils.getFullStackTrace(ex));
        return false;
    }

    @ExceptionHandler(value = { HttpRequestMethodNotSupportedException.class,
            HttpMediaTypeNotSupportedException.class })
    @ResponseStatus(value = HttpStatus.NOT_ACCEPTABLE, reason = "Not Supported")
    @ResponseBody
    public Boolean handle405Exception(Exception ex) {
        logger.error("405 Exception" + ExceptionUtils.getFullStackTrace(ex));
        return false;
    }

    @ExceptionHandler(value = { HttpMessageNotWritableException.class,
            ConversionNotSupportedException.class })
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "Internal Server Error")
    @ResponseBody
    public Boolean handle500Exception(Exception ex) {
        logger.error("500 Exception" + ExceptionUtils.getFullStackTrace(ex));
        return false;
    }

    @ExceptionHandler({ Exception.class })
    public ModelAndView handleException(Exception ex, HttpServletRequest request,
            HttpServletResponse response) {
        logger.info("*****************************************************");
        logger.error("Exception: " + ExceptionUtils.getFullStackTrace(ex));
        ex.printStackTrace();
        logger.info("*****************************************************");
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("logout");
        return modelAndView;
    }
}

这是我的 HomeController。

package com.lw.sms;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.servlet.ModelAndView;

import com.lw.sms.master.service.MasterDataService;
import com.lw.sms.user.entities.EmployeeEntity;

/**
 * Handles requests for the application home page.
 */
@Controller("homeController")
public class HomeController {

    @Autowired
    @Qualifier("masterDataServiceImpl")
    private MasterDataService masterDataService;

    @Autowired
    @Qualifier("sessionInfo")
    private SessionInfo sessionInfo;

    @GetMapping(value = { "/home", "/", "login" })
    public ModelAndView home() {
        return new ModelAndView("login");
    }

    @GetMapping(value = "dashboard")
    public ModelAndView dashboard() {

        EmployeeEntity user = sessionInfo.getEmployeeEntity();
        return new ModelAndView("dashboard", "userDetails", user);
    }

    // Logout page
    @ResponseStatus(code = HttpStatus.UNAUTHORIZED)
    @GetMapping(value = "logout")
    public String logout() {
        return "logout";
    }

}

最佳答案

能否请您尝试添加 successForwardUrl,如下所示。

 http.authorizeRequests().antMatchers("/login").permitAll()
        .antMatchers("/dashboard").access("IS_AUTHENTICATED_FULLY")
        .antMatchers("/j_spring_security_check").access("IS_AUTHENTICATED_ANONYMOUSLY")
        .and().formLogin().loginPage("/login").usernameParameter("employeeId").passwordParameter("password")
        .successForwardUrl("/dashboard").defaultSuccessUrl("/dashboard", true).failureForwardUrl("/loginfailed")
        .loginProcessingUrl("/j_spring_security_check")
        .and().logout().logoutSuccessUrl("/logout").invalidateHttpSession(true)
        .and().sessionManagement().sessionFixation().none()
        .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
        .invalidSessionUrl("/login")
        .and().exceptionHandling().accessDeniedPage("/Access_Denied").and().csrf().disable();

关于java - 未调用 Spring Security Authentication UserDetailsS​​ervice 实现类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57721464/

相关文章:

java - Guice @Inject 无法使用多个构造函数注入(inject)

java - 不能在 onEnable() 中使用成员变量

java - Jersey:LogginFeature 在哪里记录?

java - 连接到 StompClient 时我可能在哪里出错?

java - RequestMapping 值属性作为字符串变量

java - Spring 5 和 Kotlin 1.1 协程 : Type rx. 调度程序不存在

java - 在 hibernate/jpa 最佳实践问题中将分离的或新的实体与现有实体合并

java - Spring Boot-Hibernate-Mysql id 主键值序列使用@GeneratedValue 在我的所有域中共享

java - 使用 Servlet 连接到 DB2 数据库

java - 为什么更新实体会将其子实体的字段更改为空?