如何为多个身份验证提供程序提供spring安全性的java配置

时间:2016-01-17 17:49:24

标签: java spring spring-mvc spring-security

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

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

我尝试使用简单的userDetailService,我在其中发送请求到数据库中的所有表但仍然没有结果,只有一个查询正在执行而没有任何内容,我得到的唯一响应是:

  

2016-02-09 23:06:25.976 DEBUG 8780 --- [nio-8080-exec-1]   .s.a.DefaultAuthenticationEventPublisher:没有找到任何事件   例外   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:身份验证请求   失败:   org.springframework.security.authentication.InternalAuthenticationServiceException:   找不到查询的实体;嵌套异常是   javax.persistence.NoResultException:找不到查询的实体

但我永远不会抛出任何异常!!最奇怪的是,我可以在调试器中看到执行如何在em.createQuery(..)之后快速停止.getSingleResult()..就是这样,仅此而已!没有返回语句没有例外,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();
    }

2 个答案:

答案 0 :(得分:3)

只是为了澄清其他答案:

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

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

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

答案 1 :(得分:0)

如果提供商抛出AccountStatusExceptionUserDetailsService抛出UserNameNotFoundException或任何其他AuthenticationException

,则Spring Security不会尝试其他身份验证提供商

如果您希望尝试其他提供商,则loadUserByUserNameUserDetailsServiceImpl的{​​{1}}方法不应抛出OwnerDetailsService例外。

您应该决定是否要返回一个虚拟匿名UserNameNotFound对象,该对象将专门用于后备或其他一些机制,以便在UserDetails中没有用户时不抛出异常实施