如何使用Spring启动安全性使用UserDetailsS​​ervice配置多个HttpSecurity?

时间:2015-10-26 14:51:50

标签: java spring spring-security spring-boot

我正在使用spring boot安全层来验证和授权用户。现在,我想使用多http安全配置来做一些示例应用程序。我有一个场景,就像会有两个登录页面不同的URL映射(" / managementLogin"," / othersLogin")。

我可以理解如何配置多个httpsecurity配置,但我需要验证来自两个表的用户。如果管理用户登录,我需要使用UserDetailsService否则从管理表通过DAO层验证用户(如果有的话)用户登录我需要从other_users表中进行验证。

有人可以帮我了解如何使用UserDetailsService配置弹出启动安全性的多http配置和dao层吗?

这是我的基本代码段,

@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {


    @Autowired
    @Qualifier("userDetailsService")
    UserDetailsService userDetailsService;

    @Autowired
    private RESTAuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    private RESTAuthenticationFailureHandler authenticationFailureHandler;
    @Autowired
    private RESTAuthenticationSuccessHandler authenticationSuccessHandler;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // for testing authentication purpose using inMemory db
        /*
         * auth.inMemoryAuthentication().withUser("user").password("user").roles
         * ("USER").and().withUser("admin") .password("admin").roles("ADMIN");
         */

        // Dao based authentication
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/", "/home").permitAll();
        http.authorizeRequests().antMatchers("/rest/**").authenticated();
        http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);
        http.formLogin().successHandler(authenticationSuccessHandler);
        http.formLogin().failureHandler(authenticationFailureHandler);
        http.logout().logoutSuccessUrl("/");

        // CSRF tokens handling
        http.addFilterAfter(new CsrfTokenResponseHeaderBindingFilter(), CsrfFilter.class);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web
          .ignoring()
          .antMatchers("/registerUser","/register.html");
    }

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

TIA ...,

6 个答案:

答案 0 :(得分:0)

像这样实现自定义UserDetailsS​​ervice:

ranger

答案 1 :(得分:0)

使用自己的UserDetailsS​​ervice实现两个DaoAuthenticationProvider,并将两个提供程序注入authenticationManager。

我不知道两个不同的登录端点的必要条件,但起初我认为这是一个坏主意。 您可以创建不同的Authentication对象,让AuthenticationManager根据支持方法选择正确的AuthenticationProvider。

答案 2 :(得分:0)

确实,您需要使用两个用户详细信息服务。但是,这还不够。我建议你用不同的顺序创建另一个ApplicationSecurity2类。

  

Spring安全性建立在有序的过滤器链列表上。

请参阅answer此处提供的Dave Sayer。然后你可以根据需要处理不同的网址。

答案 3 :(得分:0)

在我的情况下,我检查了两个存储库,下面是我使用的一个示例:

@Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        AbstractUser user;
        try {
            user = clientRepository.findByUsername(username);
        }
        catch (Exception userException) {
            try {
                user = adminRepository.findByUsername(username);
            }
            catch (Exception adminException) {
                throw new UsernameNotFoundException("No user present with username : " + username);
            }
        }
        return user;
    }

答案 4 :(得分:0)

我必须处理相同的问题,我已经在userdetail服务中自动连接了httprequest类,并获取了请求参数类型并基于此驱动我的逻辑。

答案 5 :(得分:0)

您可以按照推荐的解决方案直接解决问题,但您可以创建一个简单的技巧来定义两个不同的 UserDetailsService,因为这里我有两个用户,一个是普通用户,另一个是编辑器:

编辑

@Log4j2
@RequiredArgsConstructor
@Service
public class EditorService implements UserDetailsService {

    private final EditorRepository editorRepository;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if(username == null || "".equals(username)){
            throw new UsernameNotFoundException("null value");
        }

        Optional<Editor> editor = editorRepository.findByUsername(username);

        if(editor.isPresent()){
            log.info("created under editor service: " + editor.get());
            return editor.get();
        }

        throw new UsernameNotFoundException("does not exists");
    }

}

用户

@Log4j2
@RequiredArgsConstructor
@Service
public class UserService implements UserDetailsService {

    private final UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if(username == null || "".equals(username)){
            throw new UsernameNotFoundException("null");
        }

        Optional<User> user = userRepository.findByUsername(username);

        if(user.isPresent()){
            log.info("cretaed under User service : " + user.get());
            return user.get();
        }

        throw new UsernameNotFoundException("does not exists");
    }
}

然后在配置方面,我们可以使用弹簧顺序机制:

用户配置:

@EnableWebSecurity
@Configuration
@RequiredArgsConstructor
@Order(1)
public class UserWebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final UserService userService;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .requestMatchers()
                .antMatchers("/user/**")
                .and()
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .httpBasic();
    }

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(this.userService).passwordEncoder(passwordEncoder());
    }
}

编辑器配置:

@EnableWebSecurity
@Configuration
@RequiredArgsConstructor
public class EditorWebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final EditorService editorService;
    @Lazy
    private final PasswordEncoder passwordEncoder;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http // all other requests handled here
                .authorizeRequests()
                .anyRequest().authenticated()
                .and()
                .httpBasic();
    }


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(this.editorService).passwordEncoder(passwordEncoder);
    }
}