Spring Boot 2.0 项目实现自同步AD域账号 顶
时间:2022-06-09
本文章向大家介绍Spring Boot 2.0 项目实现自同步AD域账号
顶
,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
在通过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
- Docker基于已有的镜像制新的镜像-Docker for Web Developers(3)
- 如何通过Remoting实现双向通信
- jenkins 入门教程(上)
- 让jQuery Tools Scrollable控件在Mobile Web里面支持resize功能
- CentOS6.5上golang环境配置
- 马斯克频发推文,或在揭示特斯拉明年大动作?
- yum安装出现No package nodejs available解决办法
- InfoPath中repeationg section动态填充数据
- CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins
- jenkins 入门教程(中)
- docker学习(1) 安装
- Ajax等待返回结果时,弹出一个友好的等待提示
- Facebook Like Button在IE上的bug
- CSS魔法堂:hasLayout原来是这样!
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 用了这个jupyter插件,我已经半个月没打开过excel了
- Webpack学习笔记
- 正则表达式学习笔记
- R 可视化 | 华夫饼图
- 绝了!Python定时爬取微博热搜+pyecharts动态图展示
- 实战 | Python爬取B站柯南弹幕+Gephi梳理主线剧情
- 别再问我 Python 怎么识别数字验证码了!
- Python自动化办公 | 同事要我帮忙补写178份Word日报!别闹!
- Excel多区间判断,其实很简单
- 外观模式
- cp命令
- java基本数据类型及相互间的转换(转)
- 【java设计模式系列】1. 工厂方法模式(Factory Method)
- 为什么 Java 中 1000==1000 为 false ?
- 【java设计模式系列】2. 单例模式(Singleton)