【问题标题】:LDAP authentication using Spring Boot使用 Spring Boot 的 LDAP 身份验证
【发布时间】:2022-01-20 16:53:55
【问题描述】:

我创建了一个 Restful API。我在这里使用 LDAP 身份验证。我们公司有一个 LDAP 目录服务器,我在我的service layer 中使用下面的方法as utility

这是我的 LDAP 身份验证方法,我将此方法用作我的服务层中的实用程序。

    public Map<String, Object> authenticate(String user, String pass) {
    String returnedAtts[] = {"sn", "givenName", "name", "userPrincipalName", "displayName", "memberOf"};
    String searchFilter = "(&(objectClass=User)(sAMAccountName=" + user + "))";
    // Create the search controls
    SearchControls searchCtls = new SearchControls();
    searchCtls.setReturningAttributes(returnedAtts);
    // Specify the search scope
    searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
    Hashtable<String, String> env = new Hashtable<String, String>();
    env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
    env.put(Context.PROVIDER_URL, ldapHost);
    env.put(Context.SECURITY_AUTHENTICATION, "simple");

    env.put(Context.SECURITY_PRINCIPAL, user + "@" + domain);
    env.put(Context.SECURITY_CREDENTIALS, pass);
    env.put(Context.SECURITY_PROTOCOL, "SSL");
    LdapContext ctxGC = null;
    NamingEnumeration<SearchResult> answer = null;
    Attributes attrs = null;
    SearchResult sr = null;
    NamingEnumeration<?> ne = null;
    Attribute attr = null;

    try {
        ctxGC = new InitialLdapContext(env, null);
        if (ctxGC != null) {
            answer = ctxGC.search(searchBase, searchFilter, searchCtls);
            if (answer != null) {
                while (answer.hasMoreElements()) {
                    sr = (SearchResult) answer.next();
                    attrs = sr.getAttributes();
                    if (attrs != null) {
                        amap = new HashMap<String, Object>();
                        ne = attrs.getAll();
                        attr = (Attribute) ne.next();
                        amap.put(attr.getID(), attr.get());
                        ne.close();
                    }
                    ctxGC.close();         // Close and clean up
                }
            } else {
                System.out.println("Answer from domen controller is null!");
            }
        } else {
            System.out.println("Login or Password is wrong! ");
        }

    } catch (NamingException ex) {
        System.out.println("Exception: "+ex.toString());
    } finally {
        System.out.println("");
    }
    return amap;
}

这是我的服务层类,我正在将实用程序类作为注入,如您所知,可以使用身份验证方法。当我使用 swagger 或邮递员用户名和密码发送请求时,给定来自请求的值,我将它们保存到表的数据库中。但在坚持之前,身份验证方法会控制我的用户名和密码。如果密码或用户名不正确,我会向客户端返回错误响应,否则我会向客户端返回成功响应。在这两种情况下,我都会从请求中将给定值插入到表的数据库中。

@Override
    public Optional<ResponseEntity<? extends ResponseDto>> login(String username, String password, String type) {

//Is there any method or feature that spring boot provides us instead of the method you see here?
        Map<String, Object> authenticate = this.controlDomainLogin.authenticate(username, password);
//Is there any method or feature that spring boot provides us instead of the method you see here?


        if (authenticate != null) {
            DomainLogin domainLogin = new DomainLogin();
            domainLogin.setUsername(username);
            domainLogin.setType(type);
            domainLogin.setLogDate(new Date());
            ResponseEntity<ResponseDto> responseDtoResponseEntity = new ResponseEntity<>(new SuccessResponseDto(SUCCESS_OPERATION.getMessage(), SUCCESS_OPERATION.getCode(), authenticate), HttpStatus.OK);
            domainLogin.setResponse(Objects.requireNonNull(responseDtoResponseEntity.getBody()).getMessage() + "," + responseDtoResponseEntity.getBody().getCode());
            this.domainLoginRepository.save(domainLogin);
            return Optional.of(responseDtoResponseEntity);
        } else {
            DomainLogin domainLogin = new DomainLogin();
            domainLogin.setUsername(username);
            domainLogin.setType(type);
            domainLogin.setLogDate(new Date());
            ResponseEntity<ResponseDto> responseDtoResponseEntity = new ResponseEntity<>(new ErrorResponseDto(WRONG_USERNAME.getMessage(), WRONG_USERNAME.getCode()), HttpStatus.NOT_FOUND);
            domainLogin.setResponse(Objects.requireNonNull(responseDtoResponseEntity.getBody()).getMessage() + "," + responseDtoResponseEntity.getBody().getCode());
            domainLogin.setException(Objects.requireNonNull(responseDtoResponseEntity.getBody()).getMessage() + "," + responseDtoResponseEntity.getBody().getCode());
            this.domainLoginRepository.save(domainLogin);
            return Optional.of(responseDtoResponseEntity);
        }
    }

现在我不需要使用这个方法了,相反,spring boot 本身有没有类似的方法或任何特性,就像我上面展示的方法一样?我的意思是我不应该使用这种方法,相反,spring boot 给我们的东西可以做同样的事情吗?

同样的操作会重复,但不同的是我会删除我用java写的方法,改用spring boot的LDAP认证方式。

如果是我下面显示的类,当我运行项目时,会出现spring默认给出的登录页面,当我在那里输入我的用户名和密码时,它会成功执行验证过程,如果失败,它给出以下警告。

ctiveDirectoryLdapAuthenticationProvider : Active Directory authentication failed: Supplied password was invalid


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider;

import java.util.Arrays;

import org.springframework.beans.factory.annotation.Value;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${ad.domain}")
    private String AD_DOMAIN;

    @Value("${ad.url}")
    private String AD_URL;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest().fullyAuthenticated()
                .and()
                .formLogin();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
        authManagerBuilder.authenticationProvider(activeDirectoryLdapAuthenticationProvider()).userDetailsService(userDetailsService());
    }

    @Bean
    public AuthenticationManager authenticationManager() {
        return new ProviderManager(Arrays.asList(activeDirectoryLdapAuthenticationProvider()));
    }
    @Bean
    public AuthenticationProvider activeDirectoryLdapAuthenticationProvider() {
        ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(AD_DOMAIN, AD_URL);
        provider.setConvertSubErrorCodesToExceptions(true);
        provider.setUseAuthenticationRequestCredentials(true);

        return provider;
    }
}

【问题讨论】:

    标签: java spring-boot api authentication ldap


    【解决方案1】:

    您可以使用 Spring Data Ldap 执行此操作。 只需用 Ldap Entry 映射 Java 类,这样你也可以对 Ldap 进行 CRUD 操作。

    创建一个从 Spring security 扩展 UserDetail 的 LdapUserService。

    然后在 Spring 安全配置中使用这个 LdapUserService。

    现在您可以执行身份验证、授权以及 CRUD 操作。

    【讨论】:

    • 你知道一个可以分享的链接吗?
    猜你喜欢
    • 2017-04-12
    • 2020-05-22
    • 1970-01-01
    • 2017-07-30
    • 1970-01-01
    • 2020-01-04
    • 2020-09-08
    • 2018-03-11
    • 2015-11-22
    相关资源
    最近更新 更多