无需将SQL Server数据库设为unsafe,如何不依赖指定命名空间获取AD用户组?
嘿,这个问题我太熟了——把数据库设为UNSAFE确实会带来安全风险,毕竟这相当于给CLR程序开了几乎无限制的权限。给你几个不用动UNSAFE就能搞定的靠谱方案:
方案1:直接用SQL Server内置的LDAP查询(完全绕开CLR)
这是最省心的方案,SQL Server本身就支持通过LDAP协议查询AD,根本不需要写CLR代码。
- 前提是你的SQL Server服务账号拥有AD的读取权限
- 示例查询代码(替换成你的域名):
SELECT sAMAccountName AS 用户名, memberOf AS 所属组 FROM OPENROWSET('ADSDSOObject', 'LDAP://DC=yourdomain,DC=com', 'SELECT sAMAccountName, memberOf FROM ''LDAP://DC=yourdomain,DC=com'' WHERE objectClass=''user''')
你也可以先通过sp_addlinkedserver创建AD链接服务器,再用OPENQUERY做更复杂的查询,灵活性更高。
方案2:用SAFE权限的CLR程序集(手动实现LDAP查询)
System.DirectoryServices.AccountManagement需要UNSAFE权限是因为它依赖了一些不在SAFE许可列表里的底层API,但我们可以直接用System.DirectoryServices这个基础命名空间——它是SQL Server默认支持的SAFE级程序集。
- 具体步骤:
- 创建一个.NET类库项目,引用
System.DirectoryServices - 编写手动查询AD用户组的代码,比如:
- 创建一个.NET类库项目,引用
using System; using System.Data.SqlClient; using System.Data.SqlTypes; using System.DirectoryServices; public class ADHelper { [Microsoft.SqlServer.Server.SqlFunction(DataAccess = Microsoft.SqlServer.Server.DataAccessKind.None)] public static SqlString GetUserADGroups(SqlString userName) { if (userName.IsNull) return SqlString.Null; // 获取当前SQL Server所在的域 string domain = Environment.UserDomainName; string ldapPath = $"LDAP://{domain}"; using (DirectoryEntry adEntry = new DirectoryEntry(ldapPath)) using (DirectorySearcher adSearcher = new DirectorySearcher(adEntry)) { // 过滤指定用户名的用户对象 adSearcher.Filter = $"(&(objectClass=user)(sAMAccountName={userName.Value}))"; adSearcher.PropertiesToLoad.Add("memberOf"); SearchResult userResult = adSearcher.FindOne(); if (userResult == null) return SqlString.Null; System.Text.StringBuilder groupList = new System.Text.StringBuilder(); foreach (string groupDN in userResult.Properties["memberOf"]) { groupList.Append(groupDN).Append(";"); } return new SqlString(groupList.ToString().TrimEnd(';')); } } }
- 编译后将程序集部署到SQL Server,设置权限为SAFE(因为只用到了官方允许的命名空间)
- 创建对应的CLR函数或存储过程调用这个方法即可
方案3:通过外部中间层代理查询
如果上面两种都不符合你的场景,还可以搞个轻量的中间服务(比如Web API、Windows服务)专门处理AD查询,然后SQL Server通过HTTP请求(SQL Server 2017+支持sys.sp_invoke_external_rest_endpoint)或者OLE自动化(sp_OACreate)调用这个中间层。
- 优点:SQL Server不需要直接访问AD,完全避开CLR权限问题;
- 缺点:需要额外维护这个中间服务,增加了架构复杂度。
最后提醒下:不管用哪种方案,都要确保执行查询的账号(SQL Server服务账号或者调用者的模拟账号)拥有AD的读取权限,不然会查不到数据哦。
内容的提问来源于stack exchange,提问作者xMilos
相关产品推荐
相关产品推荐

