当前位置: 首页 > 知识库问答 >
问题:

未调用Spring Security身份验证UserDetailsService实现类

左丘涵畅
2023-03-14

我正在尝试从基于Spring XML的配置迁移到纯Java配置,我已经配置了所有配置文件,但当我尝试在登录页面中输入用户名和密码时,它会再次将我重定向回登录页面。我相信userServiceImpl方法没有被调用,因为控件没有被调用。在这里,我有一个自动连接的userServiceImpl方法,它实现了Spring Security核心凭据的UserDetailsService。

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

}

自定义身份验证成功处理程序代码附在下面

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

这是我的家庭控制器。

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

}

共有2个答案

赵雅懿
2023-03-14

我能够复制错误。我必须在SecurityConfig文件中配置一个新bean。

import org.springframework.security.authentication.dao.DaoAuthenticationProvider;

        @Bean
        public DaoAuthenticationProvider authenticationProvider() {
            DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
            authenticationProvider.setUserDetailsService(userServiceImpl);
            authenticationProvider.setPasswordEncoder(passwordEncoder());
            return authenticationProvider;
        }
龚运乾
2023-03-14

请尝试添加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();
 类似资料:
  • 问题内容: 这是我的情况: 一个Web应用程序对许多应用程序执行某种SSO 登录的用户,而不是单击链接,该应用就会向正确的应用发布包含用户信息(名称,pwd [无用],角色)的帖子 我正在其中一个应用程序上实现SpringSecurity以从其功能中受益(会话中的权限,其类提供的方法等) 因此,我需要开发一个 自定义过滤器 -我猜想-能够从请求中检索用户信息,通过自定义 DetailsUserSe

  • JAAS 的配置 Kafka 使用Java验证和授权API(JAAS)来完成 SASL 配置. Kafka brokers 的 JAAS 的配置 KafkaServer 是每一个 KafkaServer/Broker 的 JASS 文件里面的节点名称。 在这个节点中,提供了用于所有 brokers 之间通信的 SASL 客户端连接的 SASL 配置选项。 Client 节点是用于认证 SASL 与

  • 我试图在一个反应式Spring Boot应用程序中配置一个Spring Security性,该应用程序具有一个Vuejs前端,在未经身份验证时将用户重定向到外部OpenID提供程序(用于身份验证)。在用户通过OpenID提供程序进行身份验证并重定向回应用程序(前端)后,将根据OpenID提供程序的响应创建用户名密码身份验证令牌(身份验证),并手动进行身份验证。 但是,在执行此操作时,应用程序似乎无

  • 身份验证 PDF版下载 企业应用中的URL链接可以通过OAuth2.0验证接口来获取员工的身份信息。 通过此接口获取员工身份会有一定的时间开销。对于频繁获取员工身份的场景,建议采用如下方案: 企业应用中的URL链接直接填写企业自己的页面地址; 员工跳转到企业页面时,企业校验是否有代表员工身份的cookie,此cookie由企业生成; 如果没有获取到cookie,重定向到OAuth验证链接,获取员工

  • 我正在尝试使用一个Gem devise-two-factor在Devise上实现双因素身份验证。我想验证是在2个步骤,在第一,我将要求用户名和密码。如果用户通过了这一步,那么他将被重定向到OTP的下一页,如果2FA被激活,否则会话将由Devise验证。 如果用户选择了2fa,那么我希望使用Devise来执行所有的身份验证,而不希望在User.validate_and_consume_otp(CUR

  • 我尝试postman使用用户名和密码连接到我的一个web服务,每次更改用户名时,即使用户名与我放在属性文件中的用户名不相同,请求也会被验证