使用 AD 进行用户授权和身份验证






4.60/5 (24投票s)
您花费多少时间来确保用户权限?简化工作,让 Windows 和 Active Directory 为您完成。
引言
我一直对安全问题感兴趣,特别是关于应用程序使用的安全性。我认为用户身份验证和授权是应用程序开发中的主要考虑因素之一(即使不是第一个被编码的)。
尽管我对它很感兴趣,但直到最近,我才有时间研究 .NET 在这方面提供的资源和优势。 我发现了很多东西。
Active Directory 和 LDAP
自从微软发布 Windows 2000 系列以来,就有了 Active Directory (AD)。 任何研究过它的人都知道它是基于一个不太常用的互联网协议,称为 LDAP。 它的工作基本上是在域中以一种简单的方式管理用户、组和其他安全内容。 最大的优势是互操作性,因为在进行一些工作后,可以使用另一个 LDAP 服务器替换 AD。
对于开发人员来说,.NET 提供了一个完整的命名空间来简化与 AD 和 LDAP 的工作,即 System.DirectoryServices
,其中包括 LDAP v3。 在下面的示例中,我将使用一个名为 AD1 的虚拟域。
private static string domain = "AD1";
public static bool LogonValid(string userName, string password) {
DirectoryEntry de = new DirectoryEntry(null, domain +
"\\" + userName, password);
try {
object o = de.NativeObject;
DirectorySearcher ds = new DirectorySearcher(de);
ds.Filter = "samaccountname=" + userName;
ds.PropertiesToLoad.Add("cn");
SearchResult sr = ds.FindOne();
if(sr == null) throw new Exception();
return true;
} catch {
return false;
}
}
public static bool IsInRole(string userName, string role) {
try {
role = role.ToLowerInvariant();
DirectorySearcher ds = new DirectorySearcher(new DirectoryEntry(null));
ds.Filter = "samaccountname=" + userName;
SearchResult sr = ds.FindOne();
DirectoryEntry de = sr.GetDirectoryEntry();
PropertyValueCollection dir = de.Properties["memberOf"];
for(int i = 0; i < dir.Count; ++i) {
string s = dir[i].ToString().Substring(3);
s = s.Substring(0, s.IndexOf(',')).ToLowerInvariant();
if(s == role) return true;
}
throw new Exception();
} catch {
return false;
}
}
这些方法被实现为与单个应用程序一起工作。 本文提供的源文件是 IIdentity
和 IPrincipal
接口的完整实现。 它们更适合于开发基于 AD 的 ASP.NET 窗体身份验证。
交给 Windows
应用程序可以通过使用另一组类更有效和更容易地从 Active Directory 中获益,同时避免创建自己的登录过程。 开发人员应该记住,这是一个依赖于 Windows 的解决方案。
但这是怎么可能的? 这次,我们将使用 Windows 登录本身来验证用户身份,只使用 System.Security.Principals
命名空间中的两个类。 然而,这可以通过两种方式完成
IIdentity wi = WindowsIdentity.GetCurrent();
IPrincipal wp = new WindowsPrincipal((WindowsIdentity)wi);
// ...or...
IPrincipal wp = Thread.CurrentPrincipal;
IIdentity wi = wp.Identity;
从现在开始,我们可以通过简单地调用 IPrincipal
接口定义的 IsInRole
方法来检查用户是否属于用户组。 重要的是要记住,域组必须指定域(例如“AD1\Administrators”),否则评估的组将属于运行代码的机器。
当组名仅在运行时已知时,调用 IsInRole
是一种替代方法。 一旦在设计时已知,可以使用 PrincipalPermissionAttribute
阻止方法甚至完整的类。 这可以允许访问特定的组(角色)、用户,或者只是用户已通过身份验证(记住,在 Windows 9x/ME 中,用户可以取消登录)。
[PrincipalPermission(SecurityAction.Demand, Role="AD1\\Administrators")]
[PrincipalPermission(SecurityAction.Demand, User="AD1\\harkos")]
[PrincipalPermission(SecurityAction.Demand, Authenticated=true)]
Windows 身份也可以用于验证 Intranet 站点上的用户身份。 此配置根本不需要任何代码,只需将 *web.config* 文件调整为以下几行
<authentication mode="Windows"/>
<authorization>
<allow roles="AD1\Administrators"/>
</authorization>
<identity impersonate="true"/>
最后一行不是强制性的,但它使 ASP.NET 进程模拟访问该站点的用户,从而使该站点更加安全,并允许通过 ASP.NET 代码使用 PrincipalPermissionAttributes
。
结论
使用 Windows/Active Directory 的用户身份验证和授权是保护在公司内部运行的应用程序(如 webmail 或 ERP 应用程序)的最佳方式,可以简化管理和任务委派,并避免多个密码。 当然,如果用户不应该或不需要与域用户帐户关联(例如博客或事件注册),则此处的内容均不适用。 在这些情况下,更大规模的实现(无论有没有数据库)更合适。