2009-01-31 26 views
50

Tôi có ứng dụng C# quét một thư mục và tập hợp một số thông tin. Tôi muốn hiển thị tên tài khoản cho mỗi tệp. Tôi có thể làm điều này trên hệ thống cục bộ bằng cách SID cho đối tượng FileInfo, và sau đó thực hiện:Làm cách nào để chuyển đổi từ SID sang tên tài khoản trong C#

string GetNameFromSID(SecurityIdentifier sid) 
{ 
    NTAccount ntAccount = (NTAccount)sid.Translate(typeof(NTAccount)); 
    return ntAccount.ToString(); 
} 

Tuy nhiên, điều này không làm việc cho các tập tin trên mạng, có lẽ vì các Dịch function() chỉ làm việc với tài khoản người dùng cục bộ. Tôi nghĩ có lẽ tôi có thể làm một tra cứu LDAP trên SID, vì vậy tôi thử như sau:

string GetNameFromSID(SecurityIdentifier sid) 
{ 
    string str = "LDAP://<SID=" + sid.Value + ">"; 
    DirectoryEntry dirEntry = new DirectoryEntry(str); 
    return dirEntry.Name; 
} 

Điều này có vẻ như nó sẽ làm việc, trong đó các quyền truy cập vào "dirEntry.Name" treo cứng trong vài giây, như nếu nó đang đi và truy vấn mạng, nhưng sau đó nó ném một System.Runtime.InteropServices.COMException

Có ai biết làm thế nào tôi có thể nhận được tên tài khoản của một tập tin tùy ý hoặc SID? Tôi không biết nhiều về mạng hoặc LDAP hay bất cứ thứ gì. Có một lớp được gọi là DirectorySearcher mà có lẽ tôi phải sử dụng, nhưng nó muốn có một tên miền, và tôi cũng không biết làm sao để có được điều đó - tất cả những gì tôi có là đường dẫn đến thư mục tôi đang quét.

Xin cảm ơn trước.

+0

Có thông báo cụ thể mà COMException hiển thị không? –

+0

Nó có thể là chính sách nhóm cho phép bạn duyệt qua dịch vụ thư mục cục bộ, đó là lý do tại sao bạn nhận được ngoại lệ COM. Thông báo lỗi cho thấy những gì? Hãy thử chạy filemon trên máy mạng tại sao bạn truy cập vào nó và xem kết quả. –

+0

Tôi có nghĩa là "chính sách nhóm không cho phép ..." –

Trả lời

15

Phương thức dịch của đối tượng SecurityReference hoạt động trên SID không phải cục bộ nhưng chỉ cho tài khoản miền. Đối với các tài khoản cục bộ cho một máy khác hoặc trong một thiết lập không tên miền, bạn sẽ cần phải PInvoke hàm LookupAccountSid chỉ định tên máy cụ thể mà trên đó việc tìm kiếm cần được thực hiện.

+2

Tôi vừa mới bắt đầu viết một số mã để làm một cái gì đó tương tự và thấy điều này là chính xác. P/Gọi LookupAccountSid là tốt hơn so với sử dụng SecurityIdentifier.Translate(). Tôi đang làm việc trong một môi trường nhiều rừng/miền với 60 nghìn người dùng. –

0

Cái này là một bước nhảy. Bạn đang ở trong môi trường Active Directory phải không? Chỉ cần kiểm tra :)

Nhưng dù sao, thay cho ràng buộc với sid.Value,

string str = "LDAP://<SID=" + sid.Value + ">"; 

tôi sẽ cố gắng chuyển đổi mảng byte của SID để một Octet String và ràng buộc với điều đó để thay thế.

Có một ví dụ ngọt ngào here trên trang 78. Điều này sẽ giúp bạn gần gũi hơn. Thành thật mà nói, tôi đã không cố gắng ràng buộc với một SID trước đây. Nhưng tôi đã có thành công ràng buộc với GUID của người dùng mặc dù :)

Chúc may mắn và cho tôi biết làm thế nào nó đi.

1

Ooh, khi đó có thể cuộc gọi LDAP không hoạt động vì bạn có thể không ở trong môi trường Active Directory. Nếu trường hợp này xảy ra, thì mỗi máy của bạn sẽ chịu trách nhiệm về cửa hàng nhận diện riêng của nó. Và mẫu mã đầu tiên của bạn không hoạt động trên mạng vì máy mà bạn đang thực thi mã không biết cách giải quyết SID chỉ có ý nghĩa trên máy từ xa.

Bạn thực sự nên kiểm tra xem máy của bạn có phải là một phần của Active Directory hay không. Bạn sẽ biết điều này trong quá trình đăng nhập. Hoặc bạn có thể kiểm tra bằng cách nhấp chuột phải vào "My Computer", chọn "Properties", tab "Computer Name", sau đó xem máy tính của bạn có phải là một phần của miền hay không.

-2

tôi khá chắc chắn rằng bạn sẽ có thể sử dụng câu trả lời chấp nhận từ đây: Determine the LocalSystem account name using C#

Về cơ bản, bạn có thể dịch một thể hiện của lớp SecurityIdentifier gõ NTAccount, từ đó bạn có thể nhận được tên người dùng. Trong mã:

using System.Security.Principal; 

SecurityIdentifier sid = new SecurityIdentifier("S-1-5-18"); 
NTAccount acct = (NTAccount)sid.Translate(typeof(NTAccount)); 
Console.WriteLine(acct.Value); 
+3

Trong khi điều này không chính xác, nó chỉ lặp lại mã mà người đăng đã chỉ ra không hoạt động trong tình huống của mình. –

1

Tuyệt vời. Tôi cribbed một số mã LookupAccount() từ đây:

http://www.pinvoke.net/default.aspx/advapi32.LookupAccountSid

Và đó làm việc, mặc dù tôi đã phải cung cấp máy chủ tên mình. Trong trường hợp của một con đường UNC tôi chỉ có thể lấy thành phần đầu tiên của nó. Khi nó một ổ đĩa ánh xạ, tôi sử dụng mã này để chuyển đổi đường dẫn đến một UNC một:

http://www.wiredprairie.us/blog/index.php/archives/22

Có vẻ như để làm việc, vì vậy đó là cách tôi sẽ làm điều đó, trừ khi ai đó đi lên với một tình huống trong thành phần đầu tiên của đường dẫn UNC không phải là tên máy chủ ...

Cảm ơn tất cả vì sự giúp đỡ của bạn.

37

Xem ở đây cho một câu trả lời tốt:

The best way to resolve display username by SID?

Các ý chính của nó là bit này:

string sid="S-1-5-21-789336058-507921405-854245398-9938"; 
string account = new System.Security.Principal.SecurityIdentifier(sid).Translate(typeof(System.Security.Principal.NTAccount)).ToString(); 

Cách tiếp cận này làm việc cho tôi cho phi địa phương SID của trong hoạt động thư mục.

+1

Cách tiếp cận này phù hợp với tôi. –

+1

Cảm ơn, nó đã giúp tôi lấy tên người dùng từ một miền đáng tin cậy. –

0

Lấy tên miền hiện tại:

System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain(); 

Nhận một entry thư mục từ ldap và tên miền:

DirectoryEntry de = new DirectoryEntry(string.Format("LDAP://{0}", domain)); 

Lấy sid từ một ActiveDirectoryMembershipProvider ActiveDirectoryMembershipUser:

ActiveDirectoryMembershipUser user = (ActiveDirectoryMembershipUser)Membership.GetUser(); 
var sid = (SecurityIdentifier)user.ProviderUserKey; 

Nhận tên người dùng từ SecurityIdentifier:

(NTAccount)sid.Translate(typeof(NTAccount)); 

tìm kiếm thư mục Nhận thực hiện trên một ActiveDirectory với sự gia nhập thư mục tên miền và tên người dùng:

DirectorySearcher search = new DirectorySearcher(entry); 
     search.Filter = string.Format("(SAMAccountName={0})", username); 
     search.PropertiesToLoad.Add("Name"); 
     search.PropertiesToLoad.Add("displayName"); 
     search.PropertiesToLoad.Add("company"); 
     search.PropertiesToLoad.Add("homePhone"); 
     search.PropertiesToLoad.Add("mail"); 
     search.PropertiesToLoad.Add("givenName"); 
     search.PropertiesToLoad.Add("lastLogon"); 
     search.PropertiesToLoad.Add("userPrincipalName"); 
     search.PropertiesToLoad.Add("st"); 
     search.PropertiesToLoad.Add("sn"); 
     search.PropertiesToLoad.Add("telephoneNumber"); 
     search.PropertiesToLoad.Add("postalCode"); 
     SearchResult result = search.FindOne(); 
     if (result != null) 
     { 
      foreach (string key in result.Properties.PropertyNames) 
      { 
       // Each property contains a collection of its own 
       // that may contain multiple values 
       foreach (Object propValue in result.Properties[key]) 
       { 
        outputString += key + " = " + propValue + ".<br/>"; 
       } 
      } 
     } 

Tùy thuộc vào dữ liệu trong thư mục hoạt động của bạn, bạn sẽ nhận được một phản ứng khác nhau trong đầu ra.

Here is a site that has all the user properties I needed:

5

System.DirectoryServices.AccountManagement.UserPrincipal lớp (msdn link) có chức năng tĩnh FindByIdentity để chuyển đổi một SID cho một đối tượng người dùng. Nó có thể làm việc cả với máy cục bộ hoặc máy chủ LDAP/Active Directory. Tôi chỉ sử dụng nó với thư mục hoạt động.

Dưới đây là một ví dụ mà tôi đã sử dụng trong IIS:

// Set the search context to a specific domain in active directory 
var searchContext = new PrincipalContext(ContextType.Domain, "YOURDOMAIN", "OU=SomeOU,DC=YourCompany,DC=com"); 
// get the currently logged in user from IIS 
MembershipUser aspUser = Membership.GetUser(); 
// get the SID of the user (stored in the SecurityIdentifier class) 
var sid = aspUser.ProviderUserKey as System.Security.Principal.SecurityIdentifier; 
// get the ActiveDirectory user object using the SID (sid.Value returns the SID in string form) 
var adUser = UserPrincipal.FindByIdentity(searchContext, IdentityType.Sid, sid.Value); 
// do stuff to user, look up group membership, etc. 
+1

Đây là cách thích hợp để truy vấn các tên miền nước ngoài. P/Gọi là không cần thiết. –

1

Bạn cũng có thể có được tên tài khoản của tài khoản đặc biệt như "Mọi người" với mã như thế này sẽ làm việc bất kể cài đặt ngôn ngữ của người dùng:

SecurityIdentifier everyoneSid = new SecurityIdentifier(WellKnownSidType.WorldSid, null); 
    string everyone = everyoneSid.Translate(typeof(System.Security.Principal.NTAccount)).ToString(); 
+0

Bạn vừa mới cứu mạng tôi! – lukiller

1

Trong C#, có người sử dụng SID và gán nó vào một biến chuỗi thông qua:

string strUser = System.Security.Principal.WindowsIdentity.GetCurrent().User.ToString(); 

Bạn sẽ cần sử dụng chuỗi bởi vì khả năng giải quyết cho UserName hỗ trợ chuỗi. Nói cách khác, việc sử dụng var varUser sẽ dẫn đến lỗi không gian tên.

string strUserName = new System.Security.Principal.SecurityIdentifier(strUser).Translate(typeof(System.Security.Principal.NTAccount)).ToString(); 
Các vấn đề liên quan