65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.60/5 (24投票s)

2004年11月18日

CPOL

3分钟阅读

viewsIcon

222083

downloadIcon

2114

您花费多少时间来确保用户权限?简化工作,让 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;
  }
}

这些方法被实现为与单个应用程序一起工作。 本文提供的源文件是 IIdentityIPrincipal 接口的完整实现。 它们更适合于开发基于 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 应用程序)的最佳方式,可以简化管理和任务委派,并避免多个密码。 当然,如果用户不应该或不需要与域用户帐户关联(例如博客或事件注册),则此处的内容均不适用。 在这些情况下,更大规模的实现(无论有没有数据库)更合适。

© . All rights reserved.