在MVC 4中使用Windows身份验证获取Active Directory用户信息

Mik*_*ike 13 authentication active-directory windows-authentication asp.net-mvc-4

我正在使用MVC 4 Intranet应用程序并使用Windows身份验证.我想添加到身份验证方法使用的用户对象(@User)并从活动目录中获取该数据(例如电子邮件,电话号码等).

我知道我可以创建一个自定义Authorize属性并将其添加到我所有其他控制器继承的控制器中,但我不知道这是否是正确的方法来做我想要的.

我的最终目标很简单,我希望@User对象具有通过Active Directory填充的其他属性.谢谢你尽你所能的帮助.

Chr*_*att 29

当我看到你现有的问题时,我正准备向StackOverflow添加我自己的问题,以帮助其他人解决这个问题.看起来这将是一件非常普遍的事情,但是关于如何做到这一点的信息只是在多个来源之间展开,很难追查.不仅有一个完整的资源,所以希望这对您和其他人有所帮助.

执行此操作的最佳方法是使用UserPrincipal扩展.基本上,您是UserPrincipal从子类化System.DirectoryServices.AccountManagement并添加自己的附加属性.这是通过ExtensionGetExtensionSet(有些神奇的)方法实现的.

[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);
    } 
}
Run Code Online (Sandbox Code Playgroud)

该类的两个属性需要根据您的AD实例进行自定义.DirectoryRdnPrefix需要的值是AD中的RDN(相对可分辨名称),而值DirectoryObjectClass需要是AD中userObject类的目录对象类型名称.对于典型的AD域服务设置,它们都应该与上面提供的代码一样,但对于LDS设置,它们可能不同.我添加了两个我的组织使用的新属性,"标题"和"部门".从那里,您可以了解如何添加您喜欢的任何其他属性:基本上您只需使用我在此处提供的模板创建属性.该属性可以按您喜欢的名称命名,但传递到DirectoryProperty代码块和内部的字符串值应该与AD中的属性名称匹配.有了这些,您可以使用PrincipalContext子类而不是使用UserPrincipal您需要添加的属性来获取用户对象.

UserPrincipalExtended user = UserPrincipalExtended.FindByIdentity(
    new PrincipalContext(ContextType.Domain), User.Identity.Name);
Run Code Online (Sandbox Code Playgroud)

并像在UserPrincipal实例上的任何其他属性一样访问您的属性:

// User's title
user.Title
Run Code Online (Sandbox Code Playgroud)

如果你不熟悉System.DirectoryServices.AccountManagement.UserPrincipal,有一个在烤几个用户属性:GivenName,Surname,DisplayName,等.特别是你的情况,因为你提到的电话和电子邮件具体来说,有VoiceTelephoneNumberEmailAddress.您可以在MSDN文档中查看完整列表.如果您只需要内置信息,则无需UserPrincipal按照上面的说明进行扩展.你会这样做:

UserPrincipal user = UserPrincipal.FindByIdentity(
    new PrincipalContext(ContextType.Domain), User.Identity.Name);
Run Code Online (Sandbox Code Playgroud)

但是,10次中有9次,内置插件是不够的,所以知道如何轻松完成剩下的工作是很好的.

最后,我不想在@using任何使用它的视图中添加行,所以我继续将命名空间添加到我的Views文件夹的web.config中.这部分很重要,需要将其添加到Views文件夹的web.config中,而不是项目的(Views如果您正在使用区域,则需要添加到每个区域的单个文件夹).

<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>
Run Code Online (Sandbox Code Playgroud)