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

在LDAP Spring Security中登录表单用户凭据而不是硬编码的UserDn和密码

呼延学
2023-03-14
@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAuthenticationFailureHandler customAuthFailureHandler;

    @Autowired
    private CustomAuthenticationSuccessHandler customAuthSuccessHandler;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {

        httpSecurity
            .authorizeRequests()
                .anyRequest().fullyAuthenticated()
                .and()
            .formLogin()
                .loginPage("/login").permitAll()
                .loginProcessingUrl("/sign-in")
                .usernameParameter("userid")
                .passwordParameter("password")
                .successHandler(customAuthSuccessHandler)
                .failureHandler(customAuthFailureHandler)
                .permitAll()
                .and()
            .logout()
                .logoutSuccessUrl("/logout")
                .permitAll()
                .and()
            .csrf().disable();

    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.authenticationProvider(ldapAuthProvider());

    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationProvider ldapAuthProvider() throws Exception {

        DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource("ldaps://some.domain.com:3269/");
        contextSource.setUserDn("username@domain.com"); // Here I want to set the username from Login screen
        contextSource.setPassword("password"); // also password from login screen
        contextSource.afterPropertiesSet();
        String userSearchFilter = "(sAMAccountName=username)"; // Here too I need to set username from login screen
        LdapUserSearch ldapUserSearch = new FilterBasedLdapUserSearch("dc=domain,dc=com", userSearchFilter, contextSource);
        BindAuthenticator bindAuth = new BindAuthenticator(contextSource);
        bindAuth.setUserSearch(ldapUserSearch);
        LdapAuthenticationProvider ldapAuthProvider = new LdapAuthenticationProvider(bindAuth);

        return ldapAuthProvider;
    }
}

我已经创建了一个AuthenticationProvider bean方法,并在AuthenticationManagerBuilder中设置它。我还尝试创建一个CustomAuthenticationProvider,但我不得不再次检查硬编码的用户名和密码:(

共有1个答案

邢凌
2023-03-14

我终于把它弄好了..:)我在这里找到了我想要的东西。(阿里·米斯基恩的回答)

我尝试使用CustomAuthenticationProvider方法本身,但这一次,我使用传统的JNDI LDAP方法检查身份验证。我还想检查3个不同的LDAP服务器,因此这种方法最适合我的应用程序。

以下是完整的CustomAuthenticationProvider实现

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    private static final String AT_DOMAIN_COM = "@domain.com";

    private static final String SINGLE_SPACE = " ";

    @Value("${ldap.url.for.server1}")
    private String ldapUrlForServer1; // url set in application.properties

    @Value("${ldap.url.for.server2}")
    private String ldapUrlForServer2;

    @Value("${ldap.url.for.server3}")
    private String ldapUrlForServer3;

    @Value("${ldap.jndi.context.factory}")
    private String ldapContextFactory;

    @Value("${ldap.authentication.type}")
    private String ldapAuthenticationType; // auth type is "simple"

    @Override
    public Authentication authenticate(Authentication auth) throws AuthenticationException {

        String username = auth.getName();
        String password = auth.getCredentials().toString();

        if (isLdapRegisteredUser(username, password)) {
            // use the credentials and authenticate against a third-party system
            return new UsernamePasswordAuthenticationToken(username, password, new ArrayList<>());
        } else {
            return null;
        }

    }

    boolean isLdapRegisteredUser(String username, String password) {

        boolean result = false;
        Hashtable<String, String> env = new Hashtable<>();
        LdapContext ctx = null;

        try {

            env.put(Context.INITIAL_CONTEXT_FACTORY, ldapContextFactory);
            env.put(Context.SECURITY_AUTHENTICATION, ldapAuthenticationType);
            env.put(Context.SECURITY_PRINCIPAL, username + AT_DOMAIN_COM);
            env.put(Context.SECURITY_CREDENTIALS, password);
            // here I'm checking for 3 different LDAP servers
            env.put(Context.PROVIDER_URL,  ldapUrlForServer1 + SINGLE_SPACE + ldapUrlForServer2 + SINGLE_SPACE + ldapUrlForServer3); 

            ctx = new InitialLdapContext(env, null);

            if (ctx != null) {
                result = true;
                String selectedLdapUrl = ctx.getEnvironment().get(Context.PROVIDER_URL).toString();
                // do further operations with "ctx" if needed
                System.out.println("selected LDAP url is: " + selectedLdapUrl);
                System.out.println("Connection Successful!");
            }

        } catch(NamingException nex) {
            nex.printStackTrace();
        } finally {
            if (ctx != null) {
                try {
                    ctx.close();
                } catch (Exception ex) {
                }
            }
        }

        return result;

    }


    @Override
    public boolean supports(Class<?> auth) {
        return auth.equals(UsernamePasswordAuthenticationToken.class);
    }

}

下面是我的SecurityConfig实现:

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAuthenticationProvider customAuthProvider;

    @Autowired
    private CustomAuthenticationFailureHandler customAuthFailureHandler;

    @Autowired
    private CustomAuthenticationSuccessHandler customAuthSuccessHandler;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {

        httpSecurity
            .authorizeRequests()
                .antMatchers("/css/**").permitAll()
                .antMatchers("/fonts/**").permitAll()
                .antMatchers("/images/**").permitAll()
                .antMatchers("/js/**").permitAll()
                .anyRequest().fullyAuthenticated()
                .and()
            .formLogin()
                .loginPage("/login").permitAll()
                .loginProcessingUrl("/sign-in")
                .usernameParameter("userid")
                .passwordParameter("password")
                .successHandler(customAuthSuccessHandler)
                .failureHandler(customAuthFailureHandler)
                .permitAll()
                .and()
            .logout()
                .clearAuthentication(true)
                .logoutSuccessUrl("/login").permitAll()
                .deleteCookies("JSESSIONID")
                .invalidateHttpSession(true)
                .and()
            .csrf().disable();

    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.authenticationProvider(customAuthProvider);

    }
}
 类似资料:
  • 我试图实现一个Spring Security LDAP身份验证使用WebSecurityConfigrerAdapter。 到目前为止它工作正常,但我的问题是我不希望上下文的用户名和密码被硬编码。它必须是用户的登录名和密码,所以我的问题是如何从登录表单中构建用户名和密码的上下文和设置? 这是我正在使用的代码: 非常感谢。

  • 另外,我希望在执行过程中隐藏'geckodriver.exe窗口‘。 ……余下的代码将继续....

  • 首次登陆的用户名和密码有二个,分别为: 用户名:admin     密码 :admin 用户名:user0     密码:user0 账号admin是系统管理员权限,账号user0是普通用户,属于设计角色,拥有设计权限。 在登录后,注意更改账号密码。

  • 问题内容: 我希望你能帮助我找到无需使用密码即可实现手动(服务器端启动)手动登录的最佳方法。让我解释一下工作流程: 用户注册 谢谢!带有激活链接的电子邮件已发送blablabla (帐户现已存在,但被标记为未启用) 用户打开电子邮件,单击链接 (已启用帐户) 谢谢!你现在可以使用该网站 我要做的是在用户单击电子邮件链接后登录,以便他可以立即开始使用该网站。 我无法使用他的密码,因为该密码已在数据库

  • 我正在遵循Dave Syer的基本Spring Boot OAuth2示例:https://github.com/dsyer/sparklr-boot/blob/master/src/main/java/demo/application.java 我错过了什么才能让它运转起来?

  • 问题内容: 这是一个非常简单的测试,但我似乎无法正确完成。 我想检查哪些用户可以登录并执行操作(这是一整套测试的一部分),但是第一步会引起一些问题。 当我运行测试时,我得到: 为什么我不正确登录时django返回HTTP代码? 对于其他上下文,这是我如何管理登录/注销URL: 问题答案: Web社区中有一些关于对凭证失败的正确响应的辩论。例如,这是有关从切换到的Wordpress凭单。在Stack