標(biāo)題:活動(dòng)目錄(Active Directory)小結(jié)
關(guān)鍵詞:活動(dòng)目錄?? AD??? ADSI?? LDAP
作者:JRQ
鏈接: http://blog.csdn.net/jrq/archive/2007/03/17/1531812.aspx
正文:
1.活動(dòng)目錄(AD)
? Active Directory 是用于 Windows Server 的目錄服務(wù)。
? 它存儲(chǔ)著網(wǎng)絡(luò)上各種對(duì)象的有關(guān)信息,并使該信息易于管理員和用戶查找及使用。
? Active Directory 目錄服務(wù)使用結(jié)構(gòu)化的數(shù)據(jù)存儲(chǔ)作為目錄信息的邏輯層次結(jié)構(gòu)的基礎(chǔ)。
? 通過登錄驗(yàn)證以及目錄中對(duì)象的訪問控制,將安全性集成到 Active Directory 中。
? 目錄服務(wù),如 Active Directory,提供了用于存儲(chǔ)目錄數(shù)據(jù)并使該數(shù)據(jù)可由網(wǎng)絡(luò)用戶和管理員使用的方法。
? 例如,Active Directory 存儲(chǔ)了有關(guān)用戶帳戶的信息,如名稱、密碼、電話號(hào)碼等,并允許相同網(wǎng)絡(luò)上的其他已授權(quán)用戶訪問該信息。
2.LDAP
? LDAP是輕量目錄訪問協(xié)議,英文全稱是Lightweight Directory Access Protocol。
? LDAP是基于X.500標(biāo)準(zhǔn)的。
? LDAP 僅通過使用原始 X.500目錄存取協(xié)議 (DAP) 的功能子集而減少了所需的系統(tǒng)資源消耗。
? 與X.500不同,LDAP支持TCP/IP,這對(duì)訪問Internet是必須的。
? LDAP和關(guān)系數(shù)據(jù)庫是兩種不同層次的概念,后者是存貯方式(同一層次如網(wǎng)格數(shù)據(jù)庫,對(duì)象數(shù)據(jù)庫),前者是存貯模式和訪問協(xié)議。
? LDAP是一個(gè)比關(guān)系數(shù)據(jù)庫抽象層次更高的存貯概念,與關(guān)系數(shù)據(jù)庫的查詢語言SQL屬同一級(jí)別。
3.ADSI
? 在Delphi中可以使用微軟的ADSI(活動(dòng)目錄服務(wù)接口)來訪問活動(dòng)目錄。
? ADSI是一組以COM接口的形式提供目錄服務(wù)的,是為基于目錄服務(wù)提供的通用接口。
? 一些標(biāo)準(zhǔn)的ADSI提供者(Provider)有WinNT、IIS、LDAP和NDS。
? 可以通過ADSI存取四種網(wǎng)絡(luò)目錄結(jié)構(gòu):
? WinNT (Microsoft SAM 數(shù)據(jù)庫)、LDAP (輕量目錄存取協(xié)議)、NDS (NetWare目錄服務(wù))和NWCOMPAT(Novell NetWare 3.x)。?
? ADSI可以使Windows NT 管理員的工作變得輕松。
? ADSI支持管理員執(zhí)行一些一般的管理任務(wù),比如添加新用戶、管理打印機(jī)、安全設(shè)定和控制NT域。
? 因?yàn)锳DSI使用COM接口,任何支持COM的編程語言像Delphi、BCB、VB、VC等都可以調(diào)用ADSI。
? 如在Delphi中調(diào)用ADSI,則需要引入活動(dòng)目錄類型庫。
? 操作如下:
? 在IDE中,Project--->Import Type Library。
? 選擇“Active Ds Type Library(Version 1.0)”,單擊“Create Unit”。
? Delphi會(huì)做相應(yīng)的封裝,生成ActiveDs_TLB.pas文件。
? Uses ActiveDs_TLB,就可以在Delphi程序中使用ADSI了。
4.JAVA+LDAP訪問Window 2000 Server AD。
package ADOper;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.NamingEnumeration;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import java.util.Enumeration;
public class ADOperTest {
? public ADOperTest() {
? }
? public void GetADInfo() {
??? Hashtable HashEnv = new Hashtable();
??? String LDAP_URL = "
ldap://192.168.100.3:389
"; //LDAP訪問地址
??? //String adminName = "CN=OAWebUser,CN=Users,DC=Hebmc,DC=com";//AD的用戶名
??? String adminName = "Hebmc//OAWebUser"; //注意用戶名的寫法:domain/User 或
User@domain.com
??? adminName = "
OAWebUser@Hebmc.com
"; //注意用戶名的寫法:domain/User 或
User@domain.com
??? String adminPassword = "chenzuooaup02"; //密碼
??? HashEnv.put(Context.SECURITY_AUTHENTICATION, "simple"); //LDAP訪問安全級(jí)別
??? HashEnv.put(Context.SECURITY_PRINCIPAL, adminName); //AD User
??? HashEnv.put(Context.SECURITY_CREDENTIALS, adminPassword); //AD Password
??? HashEnv.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory"); //LDAP工廠類
??? HashEnv.put(Context.PROVIDER_URL, LDAP_URL);
??? try {
????? LdapContext ctx = new InitialLdapContext(HashEnv, null);
????? SearchControls searchCtls = new SearchControls(); //Create the search controls
????? searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE); //Specify the search scope
????? String searchFilter = "objectClass=User"; //specify the LDAP search filter
????? //String searchFilter = "objectClass=organizationalUnit";//specify the LDAP search filter
????? String searchBase = "DC=Hebmc,DC=com"; //Specify the Base for the search//搜索域節(jié)點(diǎn)
????? int totalResults = 0;
????? //Specify the attributes to return
????? //String returnedAtts[] = {"memberOf"};//定制返回屬性
????? String returnedAtts[] = {
????????? "url", "whenChanged", "employeeID", "name", "userPrincipalName",
????????? "physicalDeliveryOfficeName", "departmentNumber", "telephoneNumber",
????????? "homePhone", "mobile", "department", "sAMAccountName", "whenChanged",
????????? "mail"}; //定制返回屬性
????? searchCtls.setReturningAttributes(returnedAtts); //設(shè)置返回屬性集
????? //Search for objects using the filter
????? NamingEnumeration answer = ctx.search(searchBase, searchFilter,searchCtls);
????? while (answer.hasMoreElements()) {
??????? SearchResult sr = (SearchResult) answer.next();
??????? System.out.println("************************************************");
??????? System.out.println(sr.getName());
??????? Attributes Attrs = sr.getAttributes();
??????? if (Attrs != null) {
????????? try {
??????????? for (NamingEnumeration ne = Attrs.getAll(); ne.hasMore(); ) {
????????????? Attribute Attr = (Attribute) ne.next();
????????????? System.out.println("? AttributeID=" + Attr.getID().toString());
????????????? //讀取屬性值
????????????? for (NamingEnumeration e = Attr.getAll(); e.hasMore();totalResults++) {
??????????????? System.out.println("??? AttributeValues=" + e.next().toString());
????????????? }
????????????? System.out.println("??? ---------------");
????????????? //讀取屬性值
????????????? Enumeration values = Attr.getAll();
????????????? if (values != null) { // 迭代
??????????????? while (values.hasMoreElements()) {
????????????????? System.out.println("??? AttributeValues=" + values.nextElement());
??????????????? }
????????????? }
????????????? System.out.println("??? ---------------");
??????????? }
????????? }
????????? catch (NamingException e) {
??????????? System.err.println("Throw Exception : " + e);
????????? }
??????? }
????? }
????? System.out.println("Number: " + totalResults);
????? ctx.close();
??? }
??? catch (NamingException e) {
????? e.printStackTrace();
????? System.err.println("Throw Exception :? " + e);
??? }
? }
? public static void main(String args[]) {
??? ADOperTest ad = new ADOperTest();
??? ad.GetADInfo();
? }
}
備注:
? 使用LADP訪問AD,注意用戶名的寫法:domain/User 或 User@domain.com 。
? 如用戶名不正確,則可能會(huì)出現(xiàn)如下異常:
javax.naming.AuthenticationException: [LDAP: error code 49 - 80090308: LdapErr: DSID-0C090334, comment: AcceptSecurityContext error, data 525, vece
5.Delphi7使用WinNT Provider訪問Window 2000 Server AD。
unit Unt_AD;
interface
uses
? Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
? Dialogs, StdCtrls, ComCtrls, ActiveDs_TLB, ActiveX, ComObj;
type
? TMainFrm = class(TForm)
??? grp1: TGroupBox;
??? cbUseLogin: TCheckBox;
??? lbl1: TLabel;
??? ADSIUsername: TEdit;
??? lbl2: TLabel;
??? ADSIPassword: TEdit;
??? ADSIDomainName: TEdit;
??? btn1: TButton;
??? lbl3: TLabel;
??? GroupListView: TListView;
??? ComputerListView: TListView;
??? SeverListView: TListView;
??? UserListView: TListView;
??? lbl4: TLabel;
??? lbl5: TLabel;
??? Label1: TLabel;
??? lbl6: TLabel;
??? procedure btn1Click(Sender: TObject);
? private
??? { Private declarations }
??? procedure GetDomainInformation(Domain: IADsContainer);
??? procedure AddUserToList(ADsObj:IADs);
??? procedure AddGroupToList(ADsObj:IADs);
??? procedure AddComputerToList(ADsObj:IADs);
? public
??? { Public declarations }
? end;
//連接 Win NT 目錄服務(wù)就是找到域控制器然后綁定到相應(yīng)的對(duì)象上。
//綁定可以通過 ADsGetObject 或 ADsOpenObject 函數(shù)來實(shí)現(xiàn)。
//第一個(gè)函數(shù)使用登錄用戶缺省的信任級(jí)別,
//第二個(gè)函數(shù)允許開發(fā)者指定特殊的安全信任機(jī)制來綁定 ADSI 對(duì)象。
//缺省條件下,ADsGetObject函數(shù)根據(jù)當(dāng)前用戶進(jìn)行安全認(rèn)證。
function ADsGetObject(lpszPathName: PWideChar;?? //第一個(gè)參數(shù)是對(duì)象的路徑名
????????????????????? const riid: TIID;????????? //第二個(gè)參數(shù)是對(duì)象的接口標(biāo)識(shí)符
????????????????????? out obj): HResult; stdcall; external 'activeds.dll';// 第三個(gè)參數(shù)用于返回得到的被請(qǐng)求的接口指針
//ADsOpenObject 函數(shù)在不同的安全認(rèn)證機(jī)制下綁定 ADSI 對(duì)象,
//它主要是通過調(diào)用參數(shù)返回的用戶名和口令來認(rèn)證的
function ADsOpenObject(lpszPathName: PWideChar;??? //第一個(gè)參數(shù)是對(duì)象的路徑名
?????????????????????? lpszUserName: PWideChar;??? //第二個(gè)參數(shù)是調(diào)用者提供的用戶名
?????????????????????? lpszPassword: PWideChar;??? //第三個(gè)參數(shù)是調(diào)用者提供的口令
?????????????????????? dwReserved: LongInt;??????? //第四個(gè)參數(shù)是一個(gè)保留的 provider 標(biāo)識(shí),用來確定綁定的認(rèn)證方法
?????????????????????? const riid: TIID;?????????? //第五個(gè)參數(shù)是請(qǐng)求接口的接口標(biāo)識(shí)符,
?????????????????????? out obj): HResult; stdcall; external 'activeds.dll'; //最后一個(gè)參數(shù)用來返回請(qǐng)求的接口指針。
var
? MainFrm: TMainFrm;
implementation
{$R *.dfm}
// 獲取域信息?
procedure TMainFrm.GetDomainInformation(Domain: IADsContainer);
var
? Enum: IEnumVariant;
? ADsTempObj: OLEVariant;
? ADsObj: IADs;
? Value: LongWord;
begin
? //清空用戶、組和計(jì)算機(jī)列表
? UserListView.Items.Clear;
? GroupListView.Items.Clear;
? ComputerListView.Items.Clear;
? //獲取枚舉對(duì)象,并賦值給 Enum 變量
? Enum := (Domain._NewEnum) as IEnumVariant;
? //利用枚舉對(duì)象查找,把每個(gè)子對(duì)象賦值給臨時(shí)的 OLEVariant 對(duì)象
? while (Enum.Next(1, ADsTempObj, Value) = S_OK) do
??? begin
????? ADsObj := IUnknown(ADsTempObj) as IADs;? //獲得臨時(shí)對(duì)象:OLEVariant 變量賦值給 ADSI 對(duì)象
?????
????? if AdsObj.Class_ = 'User' then??? //如果是用戶對(duì)象
????????? AddUserToList(ADsObj);
?????
????? if AdsObj.Class_ = 'Group' then?? //如果是組對(duì)象
???????? AddGroupToList(ADsObj);
?????
????? if AdsObj.Class_ = 'Computer' then //如果是計(jì)算機(jī)對(duì)象
???????? AddComputerToList(ADsObj);
?????? ADsTempObj:=Null; //釋放OLEVariant
? end;?
end;
procedure TMainFrm.AddUserToList(ADsObj:IADs);
var aListItem:TListItem;
begin
? aListItem:=UserListView.Items.Add;
? aListItem.Caption:=ADsObj.Name;
? aListItem.SubItems.Add(ADsObj.Class_);
? aListItem.SubItems.Add(ADsObj.ADsPath);
? aListItem.SubItems.Add(ADsObj.Parent);
?// aListItem.SubItems.Add(ADsObj.Get('sAMAccountName'));
end;
procedure TMainFrm.AddGroupToList(ADsObj:IADs);
var aListItem:TListItem;
begin
? aListItem:=GroupListView.Items.Add;
? aListItem.Caption:=ADsObj.Name;
? aListItem.SubItems.Add(ADsObj.Class_);
? aListItem.SubItems.Add(ADsObj.ADsPath);
end;
procedure TMainFrm.AddComputerToList(ADsObj:IADs);
var aListItem:TListItem;
begin
? aListItem:=ComputerListView.Items.Add;
? aListItem.Caption:=ADsObj.Name;
? aListItem.SubItems.Add(ADsObj.Class_);
? aListItem.SubItems.Add(ADsObj.ADsPath);
end;
procedure TMainFrm.btn1Click(Sender: TObject);
var
??? UnknownObject: IUnknown;
??? DomainPath,ADUser,ADPass: WideString;
??? Domain: IADsContainer;??????
begin
? // 指定域路徑
? DomainPath := 'WinNT://' + ADSIDomainName.Text;
? ADUser:= ADSIUsername.Text;
? ADPass:= ADSIPassword.Text;
? DomainPath := 'WinNT://Hebmc.com';
? ADUser:? ADUser:= 'Hebmc/OAWebUser'; //注意用戶名稱的寫法:domain/User 或
User@domain.com
? ADUser:=
'OAWebUser@Hebmc.com'
; //注意用戶名稱的寫法:domain/User 或
User@domain.com
? ADPass:= 'chenzuooaup02';
?
? // 如果使用用戶登錄了信息
? if cbUseLogin.Checked then? // 使用用戶登錄的信息創(chuàng)建域?qū)ο?
???? OleCheck(AdsOpenObject(PWideChar(DomainPath),
????????????? PWideChar(ADUser),
????????????? PWideChar(ADPass),
????????????? 0,
????????????? IID_IADsContainer,
????????????? UnknownObject))
? else
???? OleCheck(ADsGetObject(PWideChar(DomainPath),
????????????? IID_IADsContainer,
????????????? UnknownObject));
? // 設(shè)定域?qū)ο?
? Domain := UnknownObject as IADsContainer;
? // 從域中獲得信息列表
? GetDomainInformation(Domain);
end;
end.
備注:
? *.注意用戶名的寫法:domain/User 或 User@domain.com 。
? *.Delphi使用WinNT Provider方式訪問AD,在使用ADsObj.Get('屬性')時(shí),會(huì)有一個(gè)報(bào)錯(cuò):“高速緩存中找不到目錄屬性?!? (The directory property cannot be found in the cache)。
??? 目前該問題還不知如何解決。
? *.資料參考《Delphi深度探索-活動(dòng)目錄開發(fā)》。
??? 作者:陳?。℉ubdog)。?
http://hubdog.csdn.net/
。
6.Delphi7使用LDAP訪問Window 2000 Server AD。
unit Main;
interface
uses
? Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
? Dialogs, StdCtrls, ActiveDs_TLB, ActiveX, ComObj;
type
? TMainFrm = class(TForm)
??? Button1: TButton;
??? ObjMemo: TMemo;
??? OUMemo: TMemo;
??? UserMemo: TMemo;
??? cbUseLogin: TCheckBox;
??? Obj_Label: TLabel;
??? OU_Label: TLabel;
??? Users_Label: TLabel;
??? procedure Button1Click(Sender: TObject);
? private
??? { Private declarations }
? public
??? { Public declarations }
??? procedure GetADInfo(aUser,aPass,aDomainPath: WideString);
? end;
?
//連接 Win NT 目錄服務(wù)就是找到域控制器然后綁定到相應(yīng)的對(duì)象上。
//綁定可以通過 ADsGetObject 或 ADsOpenObject 函數(shù)來實(shí)現(xiàn)。
//第一個(gè)函數(shù)使用登錄用戶缺省的信任級(jí)別,
//第二個(gè)函數(shù)允許開發(fā)者指定特殊的安全信任機(jī)制來綁定 ADSI 對(duì)象。
//缺省條件下,ADsGetObject函數(shù)根據(jù)當(dāng)前用戶進(jìn)行安全認(rèn)證。
function ADsGetObject(lpszPathName: PWideChar;?? //第一個(gè)參數(shù)是對(duì)象的路徑名
????????????????????? const riid: TIID;????????? //第二個(gè)參數(shù)是對(duì)象的接口標(biāo)識(shí)符
????????????????????? out obj): HResult; stdcall; external 'activeds.dll';// 第三個(gè)參數(shù)用于返回得到的被請(qǐng)求的接口指針
//ADsOpenObject 函數(shù)在不同的安全認(rèn)證機(jī)制下綁定 ADSI 對(duì)象,
//它主要是通過調(diào)用參數(shù)返回的用戶名和口令來認(rèn)證的
function ADsOpenObject(lpszPathName: PWideChar;??? //第一個(gè)參數(shù)是對(duì)象的路徑名
?????????????????????? lpszUserName: PWideChar;??? //第二個(gè)參數(shù)是調(diào)用者提供的用戶名
?????????????????????? lpszPassword: PWideChar;??? //第三個(gè)參數(shù)是調(diào)用者提供的口令
?????????????????????? dwReserved: LongInt;??????? //第四個(gè)參數(shù)是一個(gè)保留的 provider 標(biāo)識(shí),用來確定綁定的認(rèn)證方法
?????????????????????? const riid: TIID;?????????? //第五個(gè)參數(shù)是請(qǐng)求接口的接口標(biāo)識(shí)符,
?????????????????????? out obj): HResult; stdcall; external 'activeds.dll'; //最后一個(gè)參數(shù)用來返回請(qǐng)求的接口指針。
var
? MainFrm: TMainFrm;
implementation
{$R *.dfm}
procedure TMainFrm.Button1Click(Sender: TObject);
var DomainPath,ADUser,ADPass: WideString;
begin
? DomainPath := 'LDAP://192.168.100.3/OU=省公司,OU=組織架構(gòu),DC=Hebmc,DC=com';//LDAP訪問AD的路徑。
? ADUser:='Hebmc/OAWebUser'; //注意用戶名稱的寫法:域名稱 + 用戶名稱 或
User@domain.com
? ADUser:='OAWebUser@Hebmc.com'; //注意用戶名稱的寫法:域名稱 + 用戶名稱 或
User@domain.com
? ADPass:='chenzuooaup02';?? //用戶密碼。
?
? GetADInfo(ADUser,ADPass,DomainPath);?
end;
procedure TMainFrm.GetADInfo(aUser,aPass,aDomainPath: WideString);
var
? UnknownObject: IUnknown;
? Enum: IEnumVariant;
? ADsTempObj: OLEVariant;
? Domain: IADsContainer;
? ADsObj: IADs;
? Value: LongWord;
begin
? // 如果使用AD用戶信息登錄
? if cbUseLogin.Checked then? // 使用用戶登錄的信息創(chuàng)建域?qū)ο?
???? OleCheck(AdsOpenObject(PWideChar(aDomainPath),
????????????? PWideChar(aUser),
????????????? PWideChar(aPass),
????????????? 0,
????????????? IID_IADsContainer,
????????????? UnknownObject))
? else
???? OleCheck(ADsGetObject(PWideChar(aDomainPath),
????????????? IID_IADsContainer,
????????????? UnknownObject));
? // 設(shè)定域?qū)ο?
? Domain := UnknownObject as IADsContainer;
? //獲取枚舉對(duì)象,并賦值給 Enum 變量
? Enum := (Domain._NewEnum) as IEnumVariant;
? //利用枚舉對(duì)象查找,把每個(gè)子對(duì)象賦值給臨時(shí)的 OLEVariant 對(duì)象
? while (Enum.Next(1, ADsTempObj, Value) = S_OK) do
??? begin
????? ADsObj := IUnknown(ADsTempObj) as IADs;? //獲得臨時(shí)對(duì)象:OLEVariant 變量賦值給 ADSI 對(duì)象
????? ObjMemo.Lines.Add(AdsObj.Class_); //對(duì)象類型
????? if AdsObj.Class_ = 'organizationalUnit' then //如果是組織單元對(duì)象
???????? OUMemo.Lines.Add(ADsObj.Name) ;
????? if AdsObj.Class_ = 'user' then //如果是用戶對(duì)象
???????? UserMemo.Lines.Add(ADsObj.Name+'(用戶代碼='+ADsObj.Get('sAMAccountName')+')');
????? //遞歸。得到組內(nèi)相關(guān)用戶。
????? GetADInfo(aUser,aPass,ADsObj.ADsPath);?
?????? ADsTempObj:=Null; //釋放OLEVariant
? end;
end;
end.
備注:
?*. 注意用戶名的寫法:domain/User 或 User@domain.com
?*. Delphi使用LDAP方式訪問AD,可以使用ADsObj.Get('屬性')時(shí)得到相關(guān)屬性值。
??? 屬性的取值域可以通過JAVA程序得到。
?
7.完。
??????????????????????????????????????????????????????????????????????????????????????? ??? ? by? JRQ
??????????????????????????????????????????????????????????????????????????? ????? ?? 2007.03.16 夜? 于石
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
