我正在使用MVC 4内部网应用程序并使用Windows身份验证。我想添加到身份验证方法使用的用户对象(@User)并从活动目录中获取该数据(例如电子邮件,电话号码等)。
我知道我可以创建一个自定义Authorize属性并将其添加到我所有其他控制器继承的控制器中,但我不知道这是否是正确的方法来做我想要的。
我的最终目标很简单,我希望@User对象具有通过Active Directory填充的其他属性。感谢您提供的任何帮助。
答案 0 :(得分:29)
当我看到您现有的问题时,我正准备将自己的问题添加到StackOverflow并使用我的解决方案来帮助其他人解决此问题。看起来这将是一件非常普遍的事情,但是关于如何做到这一点的信息只是在多个来源之间展开,很难追查。这不仅仅是一个完整的资源,所以希望这对你和其他人有所帮助。
执行此操作的最佳方法是使用UserPrincipal扩展。基本上,您从UserPrincipal
继承了System.DirectoryServices.AccountManagement
并添加了自己的附加属性。这是通过ExtensionGet
和ExtensionSet
(有点神奇)方法启用的。
[DirectoryRdnPrefix("CN")]
[DirectoryObjectClass("user")]
public class UserPrincipalExtended : UserPrincipal
{
public UserPrincipalExtended(PrincipalContext context) : base(context)
{
}
public UserPrincipalExtended(PrincipalContext context, string samAccountName, string password, bool enabled)
: base(context, samAccountName, password, enabled)
{
}
[DirectoryProperty("title")]
public string Title
{
get
{
if (ExtensionGet("title").Length != 1)
return null;
return (string)ExtensionGet("title")[0];
}
set
{
ExtensionSet( "title", value );
}
}
[DirectoryProperty("department")]
public string Department
{
get
{
if (ExtensionGet("department").Length != 1)
return null;
return (string)ExtensionGet("department")[0];
}
set
{
ExtensionSet("department", value);
}
}
public static new UserPrincipalExtended FindByIdentity(PrincipalContext context, string identityValue)
{
return (UserPrincipalExtended)FindByIdentityWithType(context, typeof(UserPrincipalExtended), identityValue);
}
public static new UserPrincipalExtended FindByIdentity(PrincipalContext context, IdentityType identityType, string identityValue)
{
return (UserPrincipalExtended)FindByIdentityWithType(context, typeof(UserPrincipalExtended), identityType, identityValue);
}
}
该类的两个属性需要根据您的AD实例进行自定义。 DirectoryRdnPrefix
的值必须是AD中的RDN(相对可分辨名称),而DirectoryObjectClass
的值必须是AD中userObject类的目录对象类型名称。对于典型的AD域服务设置,它们都应该与上面提供的代码一样,但对于LDS设置,它们可以不同。我已经添加了我的组织使用的两个新属性," title"和"部门"。从那里,您可以了解如何添加您喜欢的任何其他属性:基本上您只需使用此处提供的模板创建属性。该属性可以按您喜欢的名称命名,但传递给DirectoryProperty
和代码块内的字符串值应该与AD中的属性名称匹配。有了这些,您可以使用PrincipalContext
与您的子类而不是UserPrincipal
来获取具有您需要添加的属性的用户对象。
UserPrincipalExtended user = UserPrincipalExtended.FindByIdentity(
new PrincipalContext(ContextType.Domain), User.Identity.Name);
并像UserPrincipal
实例上的任何其他内容一样访问您的媒体资源:
// User's title
user.Title
如果您不熟悉System.DirectoryServices.AccountManagement.UserPrincipal
,则会出现以下几个用户属性:GivenName
,Surname
,DisplayName
等。特别是根据您的情况,由于您专门提到了电话和电子邮件,因此VoiceTelephoneNumber
和EmailAddress
。您可以在MSDN docs中查看完整列表。如果您只需要内置信息,则不需要像我上面所示那样扩展UserPrincipal
。你会这样做:
UserPrincipal user = UserPrincipal.FindByIdentity(
new PrincipalContext(ContextType.Domain), User.Identity.Name);
但是,10次中有9次,内置插件不够,所以知道如何轻松完成剩下的工作很好。
最后,我不想将@using
行添加到任何使用此行的视图中,因此我继续将名称空间添加到我的Views
文件夹的网页中的.config。该部分很重要,需要将其添加到Views
文件夹的web.config中,而不是项目(以及每个区域的个人Views
文件夹中,如果您和#39;重新利用区域。)
<system.web.webPages.razor>
...
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
...
<add namespace="System.DirectoryServices.AccountManagement" />
<add namespace="Namespace.For.Your.Extension" />
</namespaces>
</pages>
</system.web.webPages.razor>