文档章节

Spring Boot 2.0 项目实现自同步AD域账号

B超
 B超
发布于 07/20 11:44
字数 760
阅读 588
收藏 1

在通过Spring Boot的自动化装配功能及JDK自带的LDAP模块,可通过如下几个简单步骤实现业务系统自动同步AD域账号功能。

1. Java自带ldap搜索域账号信息核心代码:

try {
    LdapContext ctx = new InitialLdapContext(env, null);
    SearchControls searchCtls = new SearchControls();
    searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
    searchCtls.setReturningAttributes(new String[]{"name","sn","distinguishedName"});
    NamingEnumeration<SearchResult> answer = ctx.search("searchBase", "searchFilter", searchCtls);
    while (answer.hasMoreElements()) {
        SearchResult sr = (SearchResult) answer.next();
        System.out.println("<<<::[" + sr.getName()+"]::>>>>");
    }
    ctx.close();
} catch (NamingException e) {
    e.printStackTrace();
}

2. 通过application.properties增加自定义配置

quickdoc.ldap.username=michael@mxleader.cn
quickdoc.ldap.password=chenbichao
quickdoc.ldap.url=LDAP://192.168.15.100:389
quickdoc.ldap.searchBase=OU=XXX有限公司,OU=XXX集团,DC=mxleader,DC=cn

3. 增加resources/META-INFO/spring.factories文件,内容如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=cn.mxleader.quickdoc.config.LDAPConfiguration

4. 增加属性Bean文件类LDAPProerties和LDAPConfiguration类, initLdapUsers方法通过Reactor方式实现业务系统启动时自动同步AD域账号的逻辑,不会阻塞业务进程。

@SpringBootConfiguration
@ConditionalOnClass(StreamService.class)
@EnableConfigurationProperties(LDAPProperties.class)
public class LDAPConfiguration {

    private final LDAPProperties ldapProperties;

    public LDAPConfiguration(LDAPProperties ldapProperties) {
        this.ldapProperties = ldapProperties;
    }

    @Bean
    public LDAPService ldapService(ConfigService configService) {
        Properties env = new Properties();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.SECURITY_AUTHENTICATION, "simple");//"none","simple","strong"
        env.put(Context.SECURITY_PRINCIPAL, ldapProperties.getUsername());
        env.put(Context.SECURITY_CREDENTIALS, ldapProperties.getPassword());
        env.put(Context.PROVIDER_URL, ldapProperties.getUrl());
        return new LDAPServiceImpl(configService, env, ldapProperties.getSearchBase(), ldapProperties.getBlacklist());
    }

    /**
     * 初始化LDAP域账号()
     *
     * @param ldapService
     * @param userService
     * @return
     */
    @Bean
    public CommandLineRunner initLdapUsers(LDAPService ldapService,
                                           UserService userService,
                                           DiskService diskService) {
        return args -> ldapService.searchLdapUsers()
                .filter(sysUser -> userService.get(sysUser.getUsername()) == null)
                .map(userService::saveUser)
                .subscribe(sysUser -> diskService.save("我的磁盘",
                        new Authorization(sysUser.getUsername(), AuthType.PRIVATE,
                                new HashSet<AuthAction>() {{
                                    add(AuthAction.READ);
                                    add(AuthAction.WRITE);
                                    add(AuthAction.DELETE);
                                }})));
    }

}

5. 增加LDAP操作服务接口和实现类

public interface LDAPService {

    Flux<SearchResult> searchLdapItems(String searchFilter, String returnedAtts[], String searchBase)
            throws NamingException;

    Flux<SysUser> searchLdapUsers(String searchBase) throws NamingException;

    Flux<SysUser> searchLdapUsers() throws NamingException;

    Flux<SearchResult> searchLdapGroups(String searchBase) throws NamingException;

    Flux<SearchResult> searchLdapGroups() throws NamingException;
}
public class LDAPServiceImpl implements LDAPService {

    private final Properties env;
    private final String defaultSearchBase;
    private final String blacklist[];
    private static final String defaultGroupFilter = "(&(objectCategory=Group)(objectClass=group)(name=*))";
    private static final String defaultPersonFilter = "(&(objectCategory=Person)(objectClass=user)(name=*))";
    private static final String defaultGroupAtts[] = {"distinguishedName", "name"};
    private static final String defaultPersonAtts[] = {"distinguishedName", "memberOf", "name", "sAMAccountName",
            "displayName", "title", "mail", "department"};

    private final ConfigService configService;

    public LDAPServiceImpl(ConfigService configService, Properties env, String defaultSearchBase,String blacklist[]) {
        this.configService = configService;
        this.env = env;
        this.defaultSearchBase = defaultSearchBase;
        this.blacklist = blacklist;
    }

    public Flux<SearchResult> searchLdapItems(String searchFilter, String returnedAtts[], String searchBase)
            throws NamingException {
        LdapContext ctx = new InitialLdapContext(env, null);
        SearchControls searchCtls = new SearchControls();
        searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        searchCtls.setReturningAttributes(returnedAtts);
        NamingEnumeration<SearchResult> answer = ctx.search(searchBase, searchFilter, searchCtls);
        Flux<SearchResult> searchResultFlux = Flux.fromStream(Collections.list(answer).stream());
        ctx.close();
        return searchResultFlux;
    }

    public Flux<SysUser> searchLdapUsers(String searchBase) throws NamingException {
        Flux<SysUser> sysUserFlux = searchLdapItems(defaultPersonFilter, defaultPersonAtts, searchBase)
                .map(sr -> {
                    try {
                        String sn = sr.getAttributes().get("sAMAccountName").get().toString();
                        String displayName = sr.getAttributes().get("displayName").get().toString();
                        String title = sr.getAttributes().get("title").get().toString();
                        String email = sr.getAttributes().get("mail").get().toString();
                        String department = sr.getAttributes().get("department").get().toString();
                        return new SysUser(ObjectId.get(), sn, displayName, title,
                                HanyuPinyinUtil.toHanyuPinyin(displayName),
                                configService.getSysProfile().getIconMap().get("AWARD"),
                                true, department,
                                new HashSet<SysUser.Authority>() {{
                                    add(SysUser.Authority.USER);
                                }},
                                new HashSet<String>() {{
                                    add(department);
                                }},
                                email);
                    } catch (NamingException exp) {
                        exp.printStackTrace();
                        return null;
                    }
                });
        // 过滤黑名单部门人员
        if(blacklist!=null && blacklist.length>0){
            return sysUserFlux.filter(sysUser -> {
                for (String blackItem : blacklist) {
                    if(sysUser.getDepartment().startsWith(blackItem))
                        return false;
                }
                return true;
            });
        }else {
            return sysUserFlux;
        }
    }

    public Flux<SysUser> searchLdapUsers() throws NamingException {
        return searchLdapUsers(defaultSearchBase);
    }

    public Flux<SearchResult> searchLdapGroups(String searchBase) throws NamingException {
        return searchLdapItems(defaultGroupFilter, defaultGroupAtts, searchBase);
    }

    public Flux<SearchResult> searchLdapGroups() throws NamingException {
        return searchLdapGroups(defaultSearchBase);
    }

}

以上逻辑的完整代码可参考工程:https://gitee.com/mxleader/quick-doc-service

我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2ztp73q3z1gkk

© 著作权归作者所有

共有 人打赏支持
B超
粉丝 14
博文 13
码字总数 9215
作品 0
深圳
程序员
加载中

评论(2)

B超
B超
AD域是微软实现的符合LDAP标准规范的一个活动目录,可以用于企业内部的组织机构及人员管理,兼容LDAP标准的接口规范。
tianxia007
tianxia007
Ad域可以科普一下吗
Spring Boot学习笔记

多线程 Spring @transactional注解和synchronized同步锁同时使用不能同步的问题 Synchronized和@Transactional 使用时,同步失效。 属性复制 spring的BeanUtils.copyProperties用法 文件上传...

OSC_fly
07/26
0
0
Spring-boot2.0 前后端分离项目 跨域问题

将Spring-boot 从1.5.x升级到2.0后,浏览器出现跨域问题: 原因:Spring-boot2.0后 allowCredentials为false 解决方式: 1.全局设置: 注意:corsconfig 实现方法也不一样,1.5.x WebMvcConf...

驛路梨花醉美
08/20
0
0
新书上架:《Spring Boot 开发实战》基于 Kotlin + Gradle + Spring Boot 2.0 的企业级服务端开发实战

新书上架:《Spring Boot 开发实战》 — 基于 Kotlin + Gradle + Spring Boot 2.0 的企业级服务端开发实战 京东下单链接 https://item.jd.com/31178320122.html 天猫下单链接 https://detail...

程序员诗人
08/22
0
0
新书上架:《Spring Boot 开发实战》(基于 Kotlin + Gradle + Spring Boot 2.0 的企业级服务端开发实战)

新书上架:《Spring Boot 开发实战》 — 基于 Kotlin + Gradle + Spring Boot 2.0 的企业级服务端开发实战 京东下单链接 https://item.jd.com/31178320122.html 天猫下单链接 https://detail...

程序员诗人
08/05
0
0
基于Spring Boot 2.0 及MongoDB 3.6.2 实现的简单文件共享服务器

近期研究学习Spring Boot 2.0及MongoDB期间,尝试用Reactive模式实现了一个简单的文件共享服务器,可用于家庭及小型组织内部的文件共享,目前已实现如下功能: 1. 管理员及普通账号鉴权; 2....

B超
01/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

原型模式

1、原型模式-定义 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 克隆(浅度克隆->拷贝值类型或者引用,深度克隆->创建新的对象,开辟新的内存) 例如客户端知道抽象Pro...

阿元
今天
58
0
awk命令扩展使用操作

awk 中使用外部shell变量 示例1 [root@centos01 t1022]# A=888[root@centos01 t1022]# echo "" | awk -v GET_A=$A '{print GET_A}'888[root@centos01 t1022]# echo "aaaaaaaaaaaaa" | aw......

野雪球
今天
52
0
深入解析MySQL视图VIEW

Q:什么是视图?视图是干什么用的? A:视图(view)是一种虚拟存在的表,是一个逻辑表,本身并不包含数据。作为一个select语句保存在数据字典中的。   通过视图,可以展现基表的部分数据;...

IT--小哥
今天
55
0
虚拟机学习之二:垃圾收集器和内存分配策略

1.对象是否可回收 1.1引用计数算法 引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时候计数器值为0的对象就是不可能...

贾峰uk
今天
59
0
smart-doc功能使用介绍

smart-doc从8月份底开始开源发布到目前为止已经迭代了几个版本。在这里非常感谢那些敢于用smart-doc去做尝试并积极提出建议的社区用户。因此决定在本博客中重要说明下smart-doc的功能,包括使...

上官胡闹
昨天
55
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部