2017-07-13 45 views
7

下午好,C#:檢查用戶是否有權訪問服務器沒有嘗試連接

我目前面臨的一個問題,在那裏我有服務器名稱的列表,我需要驗證Windows身份驗證的用戶有權限指定的服務器名稱,而不會嘗試與指定的服務器建立連接,然後向服務器列出服務器。因此,例如:

服務器:A,B,C,d

喬有權A和d,但不是B和C等等喬應該只看到A和d在他的服務器列表。

我該如何解決這個問題?我應該從Active Directory中拉出嗎?我知道如何拉取我的用戶身份,但是在哪裏拉取服務器信息並查明用戶是否擁有權限是一個完全不同的故事。任何文檔,代碼示例,文章等都很有幫助。

事項有關的工作環境

  1. 在列表中的服務器的所有正在運行的SQL Server 2008 R2和更高的數據庫服務器。
  2. 這是一個嚴格限制的政府環境。
  3. 我無法以任何方式修改Active Directory。
  4. 如果用戶有權限,我可以整天查詢Active Directory和SQL Server。
  5. 使用第三方庫和工具未經授權。

旁註關於服務器列表

該列表存儲在數據庫中,但我不認爲與權限方面這確實有幫助。我已經通過以下SQL查詢解決了針對單個數據庫檢查權限的問題:

SELECT name 
FROM sys.databases 
WHERE HAS_DBACCESS(name) = 1 
ORDER BY name 

感謝您的幫助!

-Jamie

結論

從本質上講,我已經發現沒有可能的方式來查詢遠程服務器上的AD組而不嘗試建立連接,從而所有樣品的執行發現將用IA標記用戶帳戶。對於其他類似問題的用戶不必擔心IA對用戶的影響,我在下面列出了幾個解決方案,您可以嘗試滿足您的需求(以下所有內容在正確實施時均可用)。

解決方案

  1. 查詢在Active Directory服務器和從服務器中檢索組,如果失敗9十次中有異常信息將是「訪問被拒絕。」。如果成功,請繼續提取當前用戶的組並與從服務器拉出的組進行比較。選定的答覆這個職位結合this post和/或this post會讓你需要這個解決方案。
  2. 如果您已經通過impersonation或其他手段(SQL Server Auth),訪問服務器,那麼你可以使用下面來看看成員具有分配任何服務器角色:

    SELECT IS_SRVROLEMEMBER('public')

  3. 你也可以使用Microsoft.SqlServer.Management.Smo命名空間使用Microsoft.SqlServer.Smo程序集中的可用Login class。但是,將Microsoft.SqlServer.SqlClrProvider命名空間從GAC移動到BIN可能會也可能沒有問題。關於這方面更多的信息可以在this StackOverflow post發現,在this微軟連接螺紋,其規定如下:

客戶端應用程序不應該使用的組件從Program Files文件夾,除非他們是從特定的SDK文件夾(如 「C:\ Program Files文件(x86)的\ Microsoft SQL Server的\ 130 \ SDK」)

  • 你甚至可以做一個基本的連接測試裹着嘗試捕捉以查看連接是否可用。

    using (SqlConnection conn = new SqlConnection(connString)) { try { conn.Open(); conn.Close(); } catch (Exception e) { Console.Write($"Connection test failed: {e.Message}"); } }

  • 有少量多樣的方式來實現的總體目標,它只是取決於你的具體情況和您要如何處理它。對我而言,這些解決方案都不會起作用,因爲在每種情況下,測試都會嘗試連接到正在討論的服務器,這會由於缺少權限而標記用戶。

    +0

    你的意思是你想檢查單個服務器的syslogins嗎? – SchmitzIT

    +0

    我需要驗證用戶有權訪問數據庫服務器。我會假設沒有涉及SQL查詢,但如果有的話會很好。我假設這很可能是一個Active Directory查詢。 – lxxtacoxxl

    +0

    那麼,sys.server_principals將包含有關在服務器上創建了哪些用戶的信息。只要用戶登錄,您就可以隨時輪詢您的SQL Server,並只顯示他們已添加爲有權訪問的用戶。不知道是否有更好的AD方式,但可能必須將兩者結合使用,因爲SQL也可以接受組的成員 – SchmitzIT

    回答

    1

    如果您已經實現了Active Directory,那麼您應該通過AD組爲用戶提供服務器訪問權限,否則會產生管理噩夢。想象一下,如果John Smith作爲系統管理員加入您的公司,您是否要去每個服務器並明確地分配他的權利?更容易創建一個服務器管理員AD組,然後將其分配給服務器(或通過組策略指定服務器上的AD組和存在的權限級別)

    爲什麼這也有助於您在開發應用程序時使用內置的AD角色提供服務了這樣的事情在這裏是AD用戶名稱抓住一個用戶組的一個簡單的例子

    using System.DirectoryServices.AccountManagement; 
    
        public List<string> GetGroupNames(string userName) 
        { 
         List<string> result = new List<string>(); 
         using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "YOURDOMAINHERE")) 
         { 
          using (PrincipalSearchResult<Principal> src = UserPrincipal.FindByIdentity(pc, userName).GetGroups(pc)) 
          { 
           src.ToList().ForEach(sr => result.Add(sr.SamAccountName)); 
          } 
         } 
         return result; 
        } 
    

    編輯:所以,如果你絕對拒絕使用Active Directory組來管理權限在服務器上購買工具是不成問題的,這裏有一個類將遍歷所有本地機器組,併爲您提供這些組中的用戶列表。你可以做一些事情,比如讓它作爲服務器上的計劃任務運行(或贏取服務),並將結果保存回數據庫,以便您可以隨時查詢或構建用戶界面來獲取和監控此信息。這沒有伸手,並抓住SQL服務器的權限,你說你已經有了。

    public class MachinePermissions 
    { 
        string machineName { get; set; } 
        public List<LocalGroup> localGroups { get; set; } 
    
        public List<string> GetGroupMembers(string sGroupName) 
        { 
         List<String> myItems = new List<String>(); 
         GroupPrincipal oGroupPrincipal = GetGroup(sGroupName); 
         PrincipalSearchResult<Principal> oPrincipalSearchResult = oGroupPrincipal.GetMembers(); 
         foreach (Principal oResult in oPrincipalSearchResult) 
         { 
          myItems.Add(oResult.Name); 
         } 
         return myItems; 
        } 
    
        private GroupPrincipal GetGroup(string sGroupName) 
        { 
         PrincipalContext oPrincipalContext = GetPrincipalContext(); 
         GroupPrincipal oGroupPrincipal = GroupPrincipal.FindByIdentity(oPrincipalContext, sGroupName); 
         return oGroupPrincipal; 
        } 
    
        private PrincipalContext GetPrincipalContext() 
        { 
         PrincipalContext oPrincipalContext = new PrincipalContext(ContextType.Machine); 
         return oPrincipalContext; 
        } 
    
        public MachinePermissions() 
        { 
         machineName = Environment.MachineName; 
         PrincipalContext ctx = new PrincipalContext(ContextType.Machine, Environment.MachineName); 
         GroupPrincipal gp = new GroupPrincipal(ctx); 
         gp.Name = "*"; 
         PrincipalSearcher ps = new PrincipalSearcher(); 
         ps.QueryFilter = gp; 
         PrincipalSearchResult<Principal> result = ps.FindAll(); 
         if(result.Count() > 0) 
         { 
          localGroups = new List<LocalGroup>(); 
          foreach (Principal p in result) 
          { 
           LocalGroup g = new LocalGroup(); 
           g.groupName = p.Name; 
           g.users = GetGroupMembers(g.groupName); 
           localGroups.Add(g); 
          } 
         } 
        } 
    } 
    
    public class LocalGroup 
    { 
        public string groupName { get; set; } 
        public List<String> users { get; set; } 
    } 
    
    +0

    Active Directory是一個非常強大的工具,它使得在大型環境下的生活變得非常簡單,便於管理。我對它是如何工作的知識足夠好,但如何在我的C#代碼中獲取所需的信息卻不是。 – lxxtacoxxl

    +0

    你正在創建什麼樣的C#項目? –

    +0

    我能得到的最具描述性的是,它從已知的服務器列表中提取服務器名稱,然後將所有不是系統數據庫的數據庫從這些服務器中提取出來並顯示給用戶。允許從中選擇服務器的完整列表對用戶來說是潛在的噩夢,因爲如果IA嘗試連接到他們無權訪問的服務器,IA將鎖定他們的帳戶。除此之外,我可以給出的描述非常非常**非常有限。 – lxxtacoxxl

    0

    您可以創建AD組以訪問每個數據庫,然後添加用戶。 在您的應用程序中,您可以添加組列表並檢查用戶是否是其中的成員。

    這是常見的做法,並允許爲不同用戶的不同訪問權限創建安全場景。您只爲組設置權限,所有成員都可以從訪問權限中受益。

    +0

    無法以任何方式修改AD。非常有限的環境。不過謝謝你的想法!也許這可以幫助一個人在比我自己的環境更少的環境中工作。 – lxxtacoxxl

    相關問題