java - 如何为多个身份验证提供者提供 spring security 的 java 配置

标签 java spring spring-mvc spring-security

我将有关用户的信息存储在单独的表所有者、员工、用户中,我正在尝试在 spring security 中使用 java 配置。

我为每种用户类型创建了三个不同的身份验证提供程序,但只有用户提供程序被触发。我已经阅读了 spring security 文档,唯一的方法似乎是创建具有多个从 WebSecurityConfigurerAdapter 扩展的嵌入式类的类,但我不想这样做,因为它需要大量重复代码,有没有其他方式

我尝试使用简单的 userDetailService,在其中我向数据库中的所有表发送请求,但仍然没有结果,只执行了一个查询,什么也没有,我得到的唯一响应是:

2016-02-09 23:06:25.976 DEBUG 8780 --- [nio-8080-exec-1] .s.a.DefaultAuthenticationEventPublisher : No event was found for the exception org.springframework.security.authentication.InternalAuthenticationServiceException

2016-02-09 23:06:25.976 DEBUG 8780 --- [nio-8080-exec-1] o.s.s.w.a.www.BasicAuthenticationFilter : Authentication request for failed: org.springframework.security.authentication.InternalAuthenticationServiceException: No entity found for query; nested exception is javax.persistence.NoResultException: No entity found for query

但我从不抛出任何异常!!最奇怪的是,我可以在调试器中看到执行是如何在 em.createQuery(..).getSingleResult().. 之后迅速停止的,仅此而已!没有 return 语句,没有异常(exception),wtf!!

这是我当前配置的一部分:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth
            .authenticationProvider(createAuthenticationProvider(employeeDetailService()))
            .authenticationProvider(createAuthenticationProvider(ownerDetailsService()))
            .authenticationProvider(createAuthenticationProvider(userDetailsService()));
}
 @Bean
    public OwnerDetailsService ownerDetailsService() {
        return new OwnerDetailsService();
    }

    @Bean
    public EmployeeDetailServiceImpl employeeDetailService() {
        return new EmployeeDetailServiceImpl();
    }

    @Bean
    public UserDetailsServiceImpl userDetailsService() {
        return new UserDetailsServiceImpl();
    }

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

    @Bean
    public AuthenticationSuccessHandler authenticationSuccessHandler() {
        return new MySimpleUrlAuthenticationSuccessHendler();
    }



    private AuthenticationProvider createAuthenticationProvider(UserDetailsService service) {
    DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    provider.setUserDetailsService(service);
    provider.setPasswordEncoder(passwordEncoder());
    provider.setHideUserNotFoundExceptions(true);
    return provider;
}

用户详情服务:

  @Service
    public abstract class CustomUserDetailService implements UserDetailsService{

        @Autowired
        IDBBean dao;

        protected CustomUserDetails getUser(GetUserByNameFunction function, String name) {
            return createUser(function.get(name));
        }

        protected CustomUserDetails createUser(Authenticational user) {
            return new CustomUserDetails(user, getAuthorities(user.getAuthority()));
        }

        protected List<GrantedAuthority> getAuthorities(String authority) {
            return Collections.singletonList(new SimpleGrantedAuthority(authority));
        }
    }

实现

    public class EmployeeDetailServiceImpl extends CustomUserDetailService {

        @Override
        public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
            return super.getUser(dao::getEmployeeByEmail, email);
        }
    }

    public class OwnerDetailsService extends CustomUserDetailService {

        @Override
        public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
            return super.getUser(dao::getOwnerByEmail, email);
        }
    }

public class UserDetailsServiceImpl extends CustomUserDetailService {


    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        return super.getUser(dao::getUserByEmail, userName);
    }
}

自定义用户详细信息:

private Long id;
    private String userEmail;


    public CustomUserDetails(Authenticational user,
                             Collection<? extends GrantedAuthority> authorities) {
        super(
                user.getName(),
                user.getPassword().toLowerCase(),
                user.isEnabled(),
                true,
                true,
                true,
                authorities);
        upadateValues(user);
    }

    private void upadateValues(Authenticational user) {
        this.id = user.getId();
        this.userEmail = user.getEmail();
    }

最佳答案

只是为了澄清其他答案中的一些内容:

您的身份验证提供程序存储在 ProviderManager 中的列表中,该列表通过它们迭代您的身份验证请求。如果您的身份验证提供程序抛出 AuthenticationException(BadCredentialsException 扩展 AuthenticationException),那么 ProviderManager 将尝试另一个提供程序。如果您设置了 hideUserNotFoundExceptions 属性,那么它也会包装并忽略 UsernameNotFoundException 并在这种情况下也尝试另一个提供者。

如果我是您,我会首先在 ProviderManager 的身份验证方法中放置一个调试点。从那里您可以找出为什么没有调用其他身份验证提供程序的身份验证方法。

另外,我会考虑只有一个身份验证提供程序和一个 UserDetailsS​​ervice。在我看来,你正在做很多复杂的、并不是真正需要的操作,比如将函数传递给你的抽象实现,而你所能做的就是拥有一个 UserDetailsS​​ervice,它会向你的所有 DAO 请求一个用户。这基本上就是您想要完成的,但减去 2 个身份验证提供程序、减去 1 个抽象类和减去 2 个 UserDetailsS​​ervice 实现。

关于java - 如何为多个身份验证提供者提供 spring security 的 java 配置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34841553/

相关文章:

java - 错误 : Server Tomcat v7. 0 localhost 上的服务器无法启动。在部署 Spring-MVC 项目期间

java - 在 Wildfly 上重新部署导致内存不足 : metaspace

Spring boot (Netflix) Eureka 副本

spring - 整合jqgrid、mybatis、spring mvc和postgresql

java - Maven:缺少 Artifact org.springframework:spring:jar:4.2.6

java - 持续时间或间隔中的 Joda Time 分钟数

java - 菜单抛出异常 - android.view.WindowManager$BadTokenException : Unable to add window -- token null is not for an application

java - 在Java中调用位图类

java - "orphanRemoval = true"删除操作时未删除子对象

java - 使用 Jackson 反序列化 Json 时将 UnknownFields 保存到 map