概要
活动目录(Active Directory)是面向Windows Standard Server、Windows Enterprise Server以及 Windows Datacenter Server的目录服务。(Active Directory不能运行在Windows Web Server上,但是可以通过它对运行Windows Web Server的计算机进行管理。)Active Directory存储了有关网络对象的信息,并且让管理员和用户能够轻松地查找和使用这些信息。Active Directory使用了一种结构化的数据存储方式,并以此作为基础对目录信息进行合乎逻辑的分层组织。
Microsoft Active Directory 服务是Windows 平台的核心组件,它为用户管理网络环境各个组成要素的标识和关系提供了一种有力的手段。
功能
活动目录(Active Directory)主要提供以下功能:
①基础网络服务:包括DNS、WINS、DHCP、证书服务等。
②服务器及客户端计算机管理:管理服务器及客户端计算机账户,所有服务器及客户端计算机加入域管理并实施组策略。
③用户服务:管理用户域账户、用户信息、企业通讯录(与电子邮件系统集成)、用户组管理、用户身份认证、用户授权管理等,按省实施组管理策略。
④资源管理:管理打印机、文件共享服务等网络资源。
⑤桌面配置:系统管理员可以集中的配置各种桌面配置策略,如:界面功能的限制、应用程序执行特征限制、网络连接限制、安全配置限制等。
⑥应用系统支撑:支持财务、人事、电子邮件、企业信息门户、办公自动化、补丁管理、防病毒系统等各种应用系统。
LDAP
LDAP是轻量目录访问协议,英文全称是Lightweight Directory Access Protocol。
LDAP是基于X.500标准的。
LDAP 仅通过使用原始 X.500目录存取协议 (DAP) 的功能子集而减少了所需的系统资源消耗。
与X.500不同,LDAP支持TCP/IP,这对访问Internet是必须的。
LDAP和关系数据库是两种不同层次的概念,后者是存贮方式(同一层次如网格数据库,对象数据库),前者是存贮模式和访问协议。
LDAP是一个比关系数据库抽象层次更高的存贮概念,与关系数据库的查询语言SQL属同一级别。
开发功能
先看看System.DirectoryServices的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
namespace
System.DirectoryServices
{
[DSDescription(
"DirectoryEntryDesc"
)]
[TypeConverter(
typeof
(DirectoryEntryConverter))]
[SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)]
[EnvironmentPermission(SecurityAction.Assert, Unrestricted =
true
)]
[DirectoryServicesPermission(SecurityAction.LinkDemand, Unrestricted =
true
)]
public
class
DirectoryEntry : Component
{
[DirectoryServicesPermission(SecurityAction.Demand, Unrestricted =
true
)]
public
DirectoryEntry();
[DirectoryServicesPermission(SecurityAction.Demand, Unrestricted =
true
)]
public
DirectoryEntry(
string
path);
[DirectoryServicesPermission(SecurityAction.Demand, Unrestricted =
true
)]
public
DirectoryEntry(
string
path,
string
username,
string
password);
[DirectoryServicesPermission(SecurityAction.Demand, Unrestricted =
true
)]
public
DirectoryEntry(
string
path,
string
username,
string
password, AuthenticationTypes authenticationType);
[DirectoryServicesPermission(SecurityAction.Demand, Unrestricted =
true
)]
public
DirectoryEntry(
object
adsObject);
[DefaultValue(AuthenticationTypes.Secure)]
[DSDescription(
"DSAuthenticationType"
)]
public
AuthenticationTypes AuthenticationType {
get
;
set
; }
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[DSDescription(
"DSChildren"
)]
[Browsable(
false
)]
public
DirectoryEntries Children {
get
; }
[DSDescription(
"DSGuid"
)]
[Browsable(
false
)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public
Guid Guid {
get
; }
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(
false
)]
[DSDescription(
"DSObjectSecurity"
)]
public
ActiveDirectorySecurity ObjectSecurity {
get
;
set
; }
[DSDescription(
"DSName"
)]
[Browsable(
false
)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public
string
Name {
get
; }
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[DSDescription(
"DSNativeGuid"
)]
[Browsable(
false
)]
public
string
NativeGuid {
get
; }
[DSDescription(
"DSNativeObject"
)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(
false
)]
public
object
NativeObject {
get
; }
[DSDescription(
"DSParent"
)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(
false
)]
public
DirectoryEntry Parent {
get
; }
[DefaultValue(
null
)]
[Browsable(
false
)]
[DSDescription(
"DSPassword"
)]
public
string
Password {
set
; }
[SettingsBindable(
true
)]
[DefaultValue(
""
)]
[TypeConverter(
"System.Diagnostics.Design.StringValueConverter, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
)]
[DSDescription(
"DSPath"
)]
public
string
Path {
get
;
set
; }
[DSDescription(
"DSProperties"
)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[Browsable(
false
)]
public
PropertyCollection Properties {
get
; }
[DSDescription(
"DSSchemaClassName"
)]
[Browsable(
false
)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public
string
SchemaClassName {
get
; }
[Browsable(
false
)]
[DSDescription(
"DSSchemaEntry"
)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public
DirectoryEntry SchemaEntry {
get
; }
[DefaultValue(
true
)]
[DSDescription(
"DSUsePropertyCache"
)]
public
bool
UsePropertyCache {
get
;
set
; }
[DSDescription(
"DSUsername"
)]
[DefaultValue(
null
)]
[Browsable(
false
)]
[TypeConverter(
"System.Diagnostics.Design.StringValueConverter, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
)]
public
string
Username {
get
;
set
; }
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[ComVisible(
false
)]
[DSDescription(
"DSOptions"
)]
[Browsable(
false
)]
public
DirectoryEntryConfiguration Options {
get
; }
public
void
Close();
public
void
CommitChanges();
public
DirectoryEntry CopyTo(DirectoryEntry newParent);
public
DirectoryEntry CopyTo(DirectoryEntry newParent,
string
newName);
public
void
DeleteTree();
protected
override
void
Dispose(
bool
disposing);
public
static
bool
Exists(
string
path);
public
object
Invoke(
string
methodName,
params
object
[] args);
[ComVisible(
false
)]
public
object
InvokeGet(
string
propertyName);
[ComVisible(
false
)]
public
void
InvokeSet(
string
propertyName,
params
object
[] args);
public
void
MoveTo(DirectoryEntry newParent);
public
void
MoveTo(DirectoryEntry newParent,
string
newName);
public
void
RefreshCache();
public
void
RefreshCache(
string
[] propertyNames);
public
void
Rename(
string
newName);
}
}
|
在Active Directory中搜索
1.SearchRoot
指定搜索从哪里开始,如当前节点等
1
2
|
DirectorySearcher search =
new
DirectorySearcher();
search.SearchRoot = de;
|
2.过滤器
过滤条件是用双引号引起来的括号中的内容如"(&(objectClass=user)(|(description=Auth*)(name=m*)))"
1
|
searcher.Filter=
"(&(objectClass=user)(|(description=Auth*)(name=m*)))"
|
3.搜索范围
1
|
search.SearchScope = SearchScope.Subtree;
|
取值如下:Subtree,Base(只搜索对象中的属性,至多可以得到一个对象),OneLevel(在基对象的子集中搜索,基对象不搜索)
4.加载的属性PropertiesToLoad
对象的很多属性都不太重要,此处定义了加载到缓存中的对象属性,若没有指定,默认是对象的Path和Name属性
1
2
3
4
|
search.PropertiesToLoad.Add(
"name"
);
search.PropertiesToLoad.Add(
"description"
);
search.PropertiesToLoad.Add(
"giveName"
);
search.PropertiesToLoad.Add(
"wWWWHomePage"
);
|
5.对结果进行排序,Sort函数有两个参数,第一个是要排序的字段,第二个为排序方式SortOption有两个值,Ascending和Descending
1
|
search.Sort =
new
SortOption(
"givenName"
,SortDirection.Ascending);
|
6.开始搜索,FindAll()查找返回一个SearchResultCollection,FindOne()返回一个简单的SearchResult对象
1
|
SearchResultCollection results = searcher.FindAll();
|
根据用户帐号取得AD USER Information
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
/// <summary>
/// 根据用户账号取得AD User对象
/// </summary>
/// <param name="account"></param>
/// <returns></returns>
public
DirectoryEntry GetUserByAccount(
string
account)
{
DirectoryEntry user =
null
;
using
(DirectoryEntry entry =
new
DirectoryEntry(
this
.LDAPAddress,
this
.AdminAccount,
this
.AdminPassword, AuthenticationTypes.Secure))
{
using
(DirectorySearcher searcher =
new
DirectorySearcher(entry))
{
searcher.Filter =
"(&(objectClass=user)(sAMAccountName="
+ account +
"))"
;
searcher.SearchScope = SearchScope.Subtree;
SearchResult searchResult = searcher.FindOne();
if
(searchResult !=
null
)
{
user = searchResult.GetDirectoryEntry();
}
}
entry.Close();
}
return
user;
}
|
LDAPAddress的值
1
|
|
判断用户名字是否存在
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
//判断用户名字是否存在
[DllImport(
"advapi32.dll"
, CharSet = CharSet.Auto, SetLastError =
true
, PreserveSig =
true
)]
private
static
extern
bool
LookupAccountName(
string
lpSystemName,
string
lpAccountName,
System.IntPtr psid,
ref
int
cbsid,
StringBuilder domainName,
ref
int
cbdomainLength,
ref
int
use);
public
bool
LookUpAccount(
string
accountName)
{
//pointer an size for the SID
IntPtr sid = IntPtr.Zero;
int
sidSize = 0;
//StringBuilder and size for the domain name
StringBuilder domainName =
new
StringBuilder();
int
nameSize = 0;
//account-type variable for lookup
int
accountType = 0;
//get required buffer size
LookupAccountName(String.Empty, accountName, sid,
ref
sidSize, domainName,
ref
nameSize,
ref
accountType);
//allocate buffers
domainName =
new
StringBuilder(nameSize);
sid = Marshal.AllocHGlobal(sidSize);
//lookup the SID for the account
bool
result = LookupAccountName(String.Empty, accountName, sid,
ref
sidSize, domainName,
ref
nameSize,
ref
accountType);
if
(result)
{
if
(accountName.ToLower().IndexOf(domainName.ToString().ToLower()) < 0)
{
accountName = domainName +
"\\"
+ accountName;
}
//throw.Exception; .Show("The account is : " + accountName);
}
else
{
//MessageBox.Show("Can't find the account.");
}
Marshal.FreeHGlobal(sid);
return
result;
}
}
|
用户账号是否已处于活动状态(非禁用)
/// <summary>
/// 用户账号是否已处于活动状态(非禁用)
/// </summary>
/// <param name="user"></param>
/// <returns></returns>
private bool IsUserActive(DirectoryEntry user)
{
int val = (int)user.Properties["userAccountControl"].Value;
int flag = (int)(0x0002);
int flagExists = val & flag;
if (flagExists > 0)
return false;
else
return true;
}
用户登陆的实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
/// <summary>
/// 用户登录验证
/// </summary>
/// <param name="account">AD账号</param>
/// <param name="password">密码</param>
/// <returns>
/// <para>True:验证成功</para>
/// <para>False:验证失败,如果this.Error不为空,则为异常信息</para>
/// </returns>
public
ADLoginResult Login(
string
account,
string
password)
{
ADLoginResult result = ADLoginResult.UnSuccess;
/* Check Accout Empty */
if
(
string
.IsNullOrEmpty(account))
{
result = ADLoginResult.UnSuccess;
return
result;
}
DirectoryEntry entry =
null
;
DirectoryEntry user =
null
;
try
{
/* Check Account Exists */
entry =
this
.GetUserByAccount(account);
if
(entry !=
null
)
{
using
(entry)
{
/* Check Account Active */
if
(
this
.IsUserActive(entry))
{
/* Check Password */
using
(user =
new
DirectoryEntry(
this
.LDAPAddress, account, password, AuthenticationTypes.Secure))
{
object
obj = user.NativeObject;
user.Close();
}
user =
null
;
result = ADLoginResult.Success;
}
else
{
result = ADLoginResult.Disabled;
}
entry.Close();
}
}
else
{
result = ADLoginResult.UnSuccess;
}
}
catch
(Exception ex)
{
this
.Error = ex;
}
finally
{
if
(user !=
null
)
{
user.Close();
user.Dispose();
}
if
(entry !=
null
)
{
entry.Close();
entry.Dispose();
}
}
return
result;
}
|
修改用户密码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
/// <summary>
/// 修改用户密码
/// </summary>
/// <param name="account">AD账号</param>
/// <param name="oldPassword">旧密码</param>
/// <param name="newPassword">新密码</param>
/// <returns>
/// <para>ChangePwdResult.Success::修改成功</para>
/// <para>其它:修改失败,如果this.Error不为空,则为异常信息</para>
/// </returns>
public
ChangePwdResult ChangePassword(
string
account,
string
oldPassword,
string
newPassword)
{
ChangePwdResult result = ChangePwdResult.ChangePwdUnSuccess;
/* Check Accout Empty */
if
(
string
.IsNullOrEmpty(account))
{
return
ChangePwdResult.UserNotExists;
}
DirectoryEntry user =
null
;
/* Check Login */
ADLoginResult loginSuccess =
this
.Login(account, oldPassword);
try
{
switch
(loginSuccess)
{
case
ADLoginResult.Success:
#region [ Success ]
user =
this
.GetUserByAccount(account);
if
(user !=
null
)
{
using
(user)
{
bool
bImpSuccess =
false
;
if
(
this
.IsUseImpersonate)
{
bImpSuccess =
this
._impersonation.BeginImpersonate();
this
.ImpsersonateSuccess = bImpSuccess;
if
(!bImpSuccess)
{
/*
* 打开模拟情况下模拟失败,先将结果默认为AdminLoginUnSuccess;
* 如果密码修改成功,则会更新结果为Success;如果异常,
*/
result = ChangePwdResult.AdminLoginUnSuccess;
}
}
int
userAccountControl = Convert.ToInt32(user.Properties[
"userAccountControl"
][0]);
/* Change Password */
user.Invoke(
"SetPassword"
,
new
object
[] { newPassword });
user.CommitChanges();
if
(
this
.IsUseImpersonate
&& bImpSuccess)
{
this
._impersonation.StopImpersonate();
}
user.Close();
result = ChangePwdResult.Success;
}
user =
null
;
}
else
{
result = ChangePwdResult.UserNotExists;
}
#endregion
break
;
case
ADLoginResult.UnSuccess:
result = ChangePwdResult.WrongOldPwd;
break
;
case
ADLoginResult.Disabled:
result = ChangePwdResult.Disabled;
break
;
default
:
result = ChangePwdResult.ChangePwdUnSuccess;
break
;
}
}
catch
(Exception ex)
{
/* 模拟失败情况下,返回模拟失败 */
if
(result != ChangePwdResult.AdminLoginUnSuccess)
{
result = ChangePwdResult.ChangePwdUnSuccess;
}
this
.Error = ex;
/* Get Error */
}
finally
{
if
(user !=
null
)
{
user.Close();
user.Dispose();
}
}
return
result;
}
|
总结
AD开发主要用于SSO(单点登陆的开发),在office communication 开发中会用到.希望能对大家有帮助.
参考文献
1、 http://baike.baidu.com/view/41408.htm
欢迎各位参与讨论,如果觉得对你有帮助,请点击 推荐下,万分谢谢.
作者: spring yang
出处: http://www.cnblogs.com/springyangwc/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。