Получение информации о пользователе Active Directory с проверкой подлинности Windows в MVC 4

Я работаю над приложением MVC 4 для интрасети и использую проверку подлинности Windows. Я хотел бы добавить к объекту пользователя, который использует метод аутентификации (@User), и получить эти данные из активного каталога (например, адрес электронной почты, номер телефона и т.д.).

Я знаю, что могу создать настраиваемый атрибут Authorize и добавить его в контроллер, который наследует все мои другие контроллеры, но я не знаю, правильно ли это для того, чтобы делать то, что я хочу.

Моя конечная цель проста, я хочу, чтобы объект @User имел дополнительные свойства, которые заполняются через Active Directory. Спасибо за любую помощь, которую вы можете предложить.

Ответ 1

Я как раз собирался добавить свой собственный вопрос в 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 должно быть RDN (относительное различающееся имя) в AD, а значение для DirectoryObjectClass должно быть именем типа объекта каталога в AD для класса userObject. Для типичной настройки доменных служб AD они должны использоваться как в коде, представленном выше, но для настройки LDS они могут быть разными. Я добавил два новых свойства, которые использует моя организация: "title" и "department". Из этого вы можете получить представление о том, как добавить любое другое свойство, которое вам нравится: в основном вы просто создаете свойство, используя шаблон, который я здесь предоставил. Свойству можно назвать все, что угодно, но строковое значение, переданное в DirectoryProperty и внутри блока кода, должно совпадать с именем свойства из AD. Используя это, вы можете использовать PrincipalContext с вашим подклассом вместо UserPrincipal, чтобы вернуть пользовательский объект со свойствами, которые вам нужно добавить.

UserPrincipalExtended user = UserPrincipalExtended.FindByIdentity(
    new PrincipalContext(ContextType.Domain), User.Identity.Name);

И получите доступ к свойству, как и любой другой, в экземпляре UserPrincipal:

// User title
user.Title

Если вы не знакомы с System.DirectoryServices.AccountManagement.UserPrincipal, есть несколько свойств пользователя, испеченных в: GivenName, Surname, DisplayName и т.д. В частности, в ваших обстоятельствах, поскольку вы упомянули телефон и электронную почту конкретно, VoiceTelephoneNumber и EmailAddress. Полный список можно увидеть в Документах MSDN. Если вам нужна только встроенная информация, вам не нужно расширять UserPrincipal, как я показал выше. Вы просто сделали бы:

UserPrincipal user = UserPrincipal.FindByIdentity(
    new PrincipalContext(ContextType.Domain), User.Identity.Name);

Но, в 9 раз из 10, встроенных модулей будет недостаточно, так что хорошо знать, как легко получить остальное.

Наконец, я не хотел добавлять строки @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>

Ответ 2

[DirectoryRdnPrefix("CN")]
[DirectoryObjectClass("user")]

Они не были признаны. Вы только что создали контрольную панель в своем проекте бритвы mvc 4?

Я также не могу найти или добавить ссылку System.DirectoryServices.AccountManagement