Skip to content

Commit c91dca8

Browse files
zuohuaijungitee-org
authored andcommitted
!1039 同步域架构
Merge pull request !1039 from 冰魄少年/next
2 parents 9b56ce8 + 2682a39 commit c91dca8

File tree

11 files changed

+316
-17
lines changed

11 files changed

+316
-17
lines changed

Admin.NET/Admin.NET.Core/Entity/SysLdap.cs

+7
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,13 @@ public class SysLdap : EntityTenant
7676
[Required]
7777
public virtual string BindAttrEmployeeId { get; set; } = "EmployeeId";
7878

79+
/// <summary>
80+
/// 绑定Code属性值
81+
/// </summary>
82+
[SugarColumn(ColumnDescription = "绑定对象Code属性值", Length = 64)]
83+
[Required]
84+
public virtual string BindAttrCode { get; set; } = "objectGUID";
85+
7986
/// <summary>
8087
/// 状态
8188
/// </summary>

Admin.NET/Admin.NET.Core/Entity/SysUserLdap.cs

+6
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,10 @@ public class SysUserLdap : EntityTenant
3636
/// </summary>
3737
[SugarColumn(ColumnDescription = "对应EmployeeId", Length = 32)]
3838
public string EmployeeId { get; set; }
39+
40+
/// <summary>
41+
/// 组织代码
42+
/// </summary>
43+
[SugarColumn(ColumnDescription = "DeptCode", Length = 64)]
44+
public string DeptCode { get; set; }
3945
}

Admin.NET/Admin.NET.Core/SeedData/SysMenuSeedData.cs

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ public IEnumerable<SysMenu> HasData()
8989
new SysMenu{ Id=1310000000195, Pid=1310000000191, Title="增加", Permission="sysLdap:add", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=130 },
9090
new SysMenu{ Id=1310000000196, Pid=1310000000191, Title="删除", Permission="sysLdap:delete", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=140 },
9191
new SysMenu{ Id=1310000000197, Pid=1310000000191, Title="同步域账户", Permission="sysLdap:syncUser", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=150 },
92+
new SysMenu{ Id=1310000000198, Pid=1310000000191, Title="同步域组织", Permission="sysLdap:syncOrg", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=160 },
9293

9394
new SysMenu{ Id=1310000000301, Pid=0, Title="平台管理", Path="/platform", Name="platform", Component="Layout", Icon="ele-Menu", Type=MenuTypeEnum.Dir, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=11000 },
9495

Admin.NET/Admin.NET.Core/Service/Auth/SysLdapService.cs

+159-16
Original file line numberDiff line numberDiff line change
@@ -186,15 +186,13 @@ public async Task SyncUser(SyncSysLdapInput input)
186186
}
187187

188188
var attrs = ldapEntry.GetAttributeSet();
189+
string deptCode = GetDepartmentCode(attrs, sysLdap.BindAttrCode);
189190
if (attrs.Count == 0 || attrs.ContainsKey("OU"))
190-
SearchDnLdapUser(ldapConn, sysLdap, userLdapList, ldapEntry.Dn);
191+
SearchDnLdapUser(ldapConn, sysLdap, userLdapList, ldapEntry.Dn, deptCode);
191192
else
192193
{
193-
var sysUserLdap = new SysUserLdap
194-
{
195-
Account = !attrs.ContainsKey(sysLdap.BindAttrAccount) ? null : attrs.GetAttribute(sysLdap.BindAttrAccount)?.StringValue,
196-
EmployeeId = !attrs.ContainsKey(sysLdap.BindAttrEmployeeId) ? null : attrs.GetAttribute(sysLdap.BindAttrEmployeeId)?.StringValue
197-
};
194+
var sysUserLdap = CreateSysUserLdap(attrs, sysLdap.BindAttrAccount, sysLdap.BindAttrEmployeeId, deptCode);
195+
198196
if (string.IsNullOrEmpty(sysUserLdap.EmployeeId)) continue;
199197
userLdapList.Add(sysUserLdap);
200198
}
@@ -219,16 +217,48 @@ public async Task SyncUser(SyncSysLdapInput input)
219217
}
220218
}
221219

220+
/// <summary>
221+
/// 获取部门代码
222+
/// </summary>
223+
/// <param name="attrs"></param>
224+
/// <param name="bindAttrCode"></param>
225+
/// <returns></returns>
226+
private static string GetDepartmentCode(LdapAttributeSet attrs, string bindAttrCode)
227+
{
228+
return bindAttrCode == "objectGUID"
229+
? new Guid(attrs.GetAttribute(bindAttrCode)?.ByteValue).ToString()
230+
: attrs.GetAttribute(bindAttrCode)?.StringValue ?? "0";
231+
}
232+
233+
/// <summary>
234+
/// 创建同步对象
235+
/// </summary>
236+
/// <param name="attrs"></param>
237+
/// <param name="bindAttrAccount"></param>
238+
/// <param name="bindAttrEmployeeId"></param>
239+
/// <param name="deptCode"></param>
240+
/// <returns></returns>
241+
private static SysUserLdap CreateSysUserLdap(LdapAttributeSet attrs, string bindAttrAccount, string bindAttrEmployeeId, string deptCode)
242+
{
243+
return new SysUserLdap
244+
{
245+
Account = !attrs.ContainsKey(bindAttrAccount) ? null : attrs.GetAttribute(bindAttrAccount)?.StringValue,
246+
EmployeeId = !attrs.ContainsKey(bindAttrEmployeeId) ? null : attrs.GetAttribute(bindAttrEmployeeId)?.StringValue,
247+
DeptCode = deptCode
248+
};
249+
}
250+
222251
/// <summary>
223252
/// 遍历查询域用户
224253
/// </summary>
225-
/// <param name="conn"></param>
226-
/// <param name="ldap"></param>
254+
/// <param name="ldapConn"></param>
255+
/// <param name="sysLdap"></param>
227256
/// <param name="userLdapList"></param>
228257
/// <param name="baseDn"></param>
229-
private static void SearchDnLdapUser(LdapConnection conn, SysLdap ldap, List<SysUserLdap> userLdapList, string baseDn)
258+
/// <param name="deptCode"></param>
259+
private static void SearchDnLdapUser(LdapConnection ldapConn, SysLdap sysLdap, List<SysUserLdap> userLdapList, string baseDn, string deptCode)
230260
{
231-
var ldapSearchResults = conn.Search(baseDn, LdapConnection.ScopeOne, "(objectClass=*)", null, false);
261+
var ldapSearchResults = ldapConn.Search(baseDn, LdapConnection.ScopeOne, "(objectClass=*)", null, false);
232262
while (ldapSearchResults.HasMore())
233263
{
234264
LdapEntry ldapEntry;
@@ -243,18 +273,131 @@ private static void SearchDnLdapUser(LdapConnection conn, SysLdap ldap, List<Sys
243273
}
244274

245275
var attrs = ldapEntry.GetAttributeSet();
276+
deptCode = GetDepartmentCode(attrs, sysLdap.BindAttrCode);
277+
246278
if (attrs.Count == 0 || attrs.ContainsKey("OU"))
247-
SearchDnLdapUser(conn, ldap, userLdapList, ldapEntry.Dn);
279+
SearchDnLdapUser(ldapConn, sysLdap, userLdapList, ldapEntry.Dn, deptCode);
248280
else
249281
{
250-
var sysUserLdap = new SysUserLdap
251-
{
252-
Account = !attrs.ContainsKey(ldap.BindAttrAccount) ? null : attrs.GetAttribute(ldap.BindAttrAccount)?.StringValue,
253-
EmployeeId = !attrs.ContainsKey(ldap.BindAttrEmployeeId) ? null : attrs.GetAttribute(ldap.BindAttrEmployeeId)?.StringValue
254-
};
282+
var sysUserLdap = CreateSysUserLdap(attrs, sysLdap.BindAttrAccount, sysLdap.BindAttrEmployeeId, deptCode);
283+
255284
if (string.IsNullOrEmpty(sysUserLdap.EmployeeId)) continue;
256285
userLdapList.Add(sysUserLdap);
257286
}
258287
}
259288
}
289+
290+
/// <summary>
291+
/// 同步域组织 🔖
292+
/// </summary>
293+
/// <param name="input"></param>
294+
/// <returns></returns>
295+
[DisplayName("同步域组织")]
296+
public async Task SyncDept(SyncSysLdapInput input)
297+
{
298+
var sysLdap = await _sysLdapRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
299+
var ldapConn = new LdapConnection();
300+
try
301+
{
302+
ldapConn.Connect(sysLdap.Host, sysLdap.Port);
303+
ldapConn.Bind(sysLdap.Version, sysLdap.BindDn, sysLdap.BindPass);
304+
var ldapSearchResults = ldapConn.Search(sysLdap.BaseDn, LdapConnection.ScopeOne, "(objectClass=*)", null, false);
305+
var listOrgs = new List<SysOrg>();
306+
while (ldapSearchResults.HasMore())
307+
{
308+
LdapEntry ldapEntry;
309+
try
310+
{
311+
ldapEntry = ldapSearchResults.Next();
312+
if (ldapEntry == null) continue;
313+
}
314+
catch (LdapException)
315+
{
316+
continue;
317+
}
318+
319+
var attrs = ldapEntry.GetAttributeSet();
320+
if (attrs.Count == 0 || attrs.ContainsKey("OU"))
321+
{
322+
var sysOrg = CreateSysOrg(attrs, sysLdap, listOrgs, new SysOrg { Id = 0, Level = 0 });
323+
listOrgs.Add(sysOrg);
324+
325+
SearchDnLdapDept(ldapConn, sysLdap, listOrgs, ldapEntry.Dn, sysOrg);
326+
}
327+
}
328+
329+
if (listOrgs.Count == 0)
330+
return;
331+
332+
await App.GetRequiredService<SysOrgService>().BatchAddOrgs(listOrgs);
333+
}
334+
catch (LdapException e)
335+
{
336+
throw e.ResultCode switch
337+
{
338+
LdapException.NoSuchObject or LdapException.NoSuchAttribute => Oops.Oh(ErrorCodeEnum.D0009),
339+
_ => Oops.Oh(e.Message),
340+
};
341+
}
342+
finally
343+
{
344+
ldapConn.Disconnect();
345+
}
346+
}
347+
348+
/// <summary>
349+
/// 遍历查询域用户
350+
/// </summary>
351+
/// <param name="ldapConn"></param>
352+
/// <param name="sysLdap"></param>
353+
/// <param name="listOrgs"></param>
354+
/// <param name="baseDn"></param>
355+
/// <param name="org"></param>
356+
private static void SearchDnLdapDept(LdapConnection ldapConn, SysLdap sysLdap, List<SysOrg> listOrgs, string baseDn, SysOrg org)
357+
{
358+
var ldapSearchResults = ldapConn.Search(baseDn, LdapConnection.ScopeOne, "(objectClass=*)", null, false);
359+
while (ldapSearchResults.HasMore())
360+
{
361+
LdapEntry ldapEntry;
362+
try
363+
{
364+
ldapEntry = ldapSearchResults.Next();
365+
if (ldapEntry == null) continue;
366+
}
367+
catch (LdapException)
368+
{
369+
continue;
370+
}
371+
372+
var attrs = ldapEntry.GetAttributeSet();
373+
if (attrs.Count == 0 || attrs.ContainsKey("OU"))
374+
{
375+
var sysOrg = CreateSysOrg(attrs, sysLdap, listOrgs, org);
376+
listOrgs.Add(sysOrg);
377+
378+
SearchDnLdapDept(ldapConn, sysLdap, listOrgs, ldapEntry.Dn, sysOrg);
379+
}
380+
}
381+
}
382+
383+
/// <summary>
384+
/// 创建架构对象
385+
/// </summary>
386+
/// <param name="attrs"></param>
387+
/// <param name="sysLdap"></param>
388+
/// <param name="listOrgs"></param>
389+
/// <param name="org"></param>
390+
/// <returns></returns>
391+
private static SysOrg CreateSysOrg(LdapAttributeSet attrs, SysLdap sysLdap, List<SysOrg> listOrgs, SysOrg org)
392+
{
393+
return new SysOrg
394+
{
395+
Pid = org.Id,
396+
Id = YitIdHelper.NextId(),
397+
Code = !attrs.ContainsKey(sysLdap.BindAttrCode) ? null : new Guid(attrs.GetAttribute(sysLdap.BindAttrCode)?.ByteValue).ToString(),
398+
Level = org.Level + 1,
399+
Name = !attrs.ContainsKey(sysLdap.BindAttrAccount) ? null : attrs.GetAttribute(sysLdap.BindAttrAccount)?.StringValue,
400+
OrderNo = listOrgs.Count + 1,
401+
};
402+
}
260403
}

Admin.NET/Admin.NET.Core/Service/Org/SysOrgService.cs

+13
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,19 @@ public async Task<long> AddOrg(AddOrgInput input)
129129
return newOrg.Id;
130130
}
131131

132+
/// <summary>
133+
/// 批量增加机构
134+
/// </summary>
135+
/// <param name="list"></param>
136+
/// <returns></returns>
137+
[NonAction]
138+
public async Task BatchAddOrgs(List<SysOrg> list)
139+
{
140+
DeleteAllUserOrgCache(0, 0);
141+
await _sysOrgRep.AsDeleteable().ExecuteCommandAsync();
142+
await _sysOrgRep.AsInsertable(list).ExecuteCommandAsync();
143+
}
144+
132145
/// <summary>
133146
/// 更新机构 🔖
134147
/// </summary>

Web/src/api-services/apis/sys-ldap-api.ts

+83
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,54 @@ export const SysLdapApiAxiosParamCreator = function (configuration?: Configurati
319319
options: localVarRequestOptions,
320320
};
321321
},
322+
/**
323+
*
324+
* @summary 同步域组织 🔖
325+
* @param {SyncSysLdapInput} [body]
326+
* @param {*} [options] Override http request option.
327+
* @throws {RequiredError}
328+
*/
329+
apiSysLdapSyncOrgPost: async (body?: SyncSysLdapInput, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
330+
const localVarPath = `/api/sysLdap/syncOrg`;
331+
// use dummy base URL string because the URL constructor only accepts absolute URLs.
332+
const localVarUrlObj = new URL(localVarPath, 'https://example.com');
333+
let baseOptions;
334+
if (configuration) {
335+
baseOptions = configuration.baseOptions;
336+
}
337+
const localVarRequestOptions :AxiosRequestConfig = { method: 'POST', ...baseOptions, ...options};
338+
const localVarHeaderParameter = {} as any;
339+
const localVarQueryParameter = {} as any;
340+
341+
// authentication Bearer required
342+
// http bearer authentication required
343+
if (configuration && configuration.accessToken) {
344+
const accessToken = typeof configuration.accessToken === 'function'
345+
? await configuration.accessToken()
346+
: await configuration.accessToken;
347+
localVarHeaderParameter["Authorization"] = "Bearer " + accessToken;
348+
}
349+
350+
localVarHeaderParameter['Content-Type'] = 'application/json-patch+json';
351+
352+
const query = new URLSearchParams(localVarUrlObj.search);
353+
for (const key in localVarQueryParameter) {
354+
query.set(key, localVarQueryParameter[key]);
355+
}
356+
for (const key in options.params) {
357+
query.set(key, options.params[key]);
358+
}
359+
localVarUrlObj.search = (new URLSearchParams(query)).toString();
360+
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
361+
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
362+
const needsSerialization = (typeof body !== "string") || localVarRequestOptions.headers['Content-Type'] === 'application/json';
363+
localVarRequestOptions.data = needsSerialization ? JSON.stringify(body !== undefined ? body : {}) : (body || "");
364+
365+
return {
366+
url: localVarUrlObj.pathname + localVarUrlObj.search + localVarUrlObj.hash,
367+
options: localVarRequestOptions,
368+
};
369+
},
322370
/**
323371
*
324372
* @summary 更新系统域登录配置 🔖
@@ -459,6 +507,20 @@ export const SysLdapApiFp = function(configuration?: Configuration) {
459507
return axios.request(axiosRequestArgs);
460508
};
461509
},
510+
/**
511+
*
512+
* @summary 同步域组织 🔖
513+
* @param {SyncSysLdapInput} [body]
514+
* @param {*} [options] Override http request option.
515+
* @throws {RequiredError}
516+
*/
517+
async apiSysLdapSyncOrgPost(body?: SyncSysLdapInput, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => Promise<AxiosResponse<void>>> {
518+
const localVarAxiosArgs = await SysLdapApiAxiosParamCreator(configuration).apiSysLdapSyncOrgPost(body, options);
519+
return (axios: AxiosInstance = globalAxios, basePath: string = BASE_PATH) => {
520+
const axiosRequestArgs :AxiosRequestConfig = {...localVarAxiosArgs.options, url: basePath + localVarAxiosArgs.url};
521+
return axios.request(axiosRequestArgs);
522+
};
523+
},
462524
/**
463525
*
464526
* @summary 更新系统域登录配置 🔖
@@ -541,6 +603,16 @@ export const SysLdapApiFactory = function (configuration?: Configuration, basePa
541603
async apiSysLdapSyncUserPost(body?: SyncSysLdapInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
542604
return SysLdapApiFp(configuration).apiSysLdapSyncUserPost(body, options).then((request) => request(axios, basePath));
543605
},
606+
/**
607+
*
608+
* @summary 同步域组织 🔖
609+
* @param {SyncSysLdapInput} [body]
610+
* @param {*} [options] Override http request option.
611+
* @throws {RequiredError}
612+
*/
613+
async apiSysLdapSyncOrgPost(body?: SyncSysLdapInput, options?: AxiosRequestConfig): Promise<AxiosResponse<void>> {
614+
return SysLdapApiFp(configuration).apiSysLdapSyncOrgPost(body, options).then((request) => request(axios, basePath));
615+
},
544616
/**
545617
*
546618
* @summary 更新系统域登录配置 🔖
@@ -626,6 +698,17 @@ export class SysLdapApi extends BaseAPI {
626698
public async apiSysLdapSyncUserPost(body?: SyncSysLdapInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
627699
return SysLdapApiFp(this.configuration).apiSysLdapSyncUserPost(body, options).then((request) => request(this.axios, this.basePath));
628700
}
701+
/**
702+
*
703+
* @summary 同步域组织 🔖
704+
* @param {SyncSysLdapInput} [body]
705+
* @param {*} [options] Override http request option.
706+
* @throws {RequiredError}
707+
* @memberof SysLdapApi
708+
*/
709+
public async apiSysLdapSyncOrgPost(body?: SyncSysLdapInput, options?: AxiosRequestConfig) : Promise<AxiosResponse<void>> {
710+
return SysLdapApiFp(this.configuration).apiSysLdapSyncOrgPost(body, options).then((request) => request(this.axios, this.basePath));
711+
}
629712
/**
630713
*
631714
* @summary 更新系统域登录配置 🔖

Web/src/api-services/models/add-sys-ldap-input.ts

+8
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,14 @@ export interface AddSysLdapInput {
165165
*/
166166
bindAttrEmployeeId: string;
167167

168+
/**
169+
* 绑定Code属性值
170+
*
171+
* @type {string}
172+
* @memberof AddSysLdapInput
173+
*/
174+
bindAttrCode: string;
175+
168176
/**
169177
* @type {StatusEnum}
170178
* @memberof AddSysLdapInput

0 commit comments

Comments
 (0)