web-dev-qa-db-ja.com

MVC4のWindows認証でActiveDirectoryユーザー情報を取得する

私はMVC4イントラネットアプリケーションに取り組んでおり、Windows認証を使用しています。認証方法が使用するユーザーオブジェクト(@User)に追加し、Active Directoryからそのデータ(電子メール、電話番号など)を取得したいと思います。

カスタムのAuthorize属性を作成して、他のすべてのコントローラーが継承するコントローラーに追加できることは知っていますが、これが私が望むことを行うための正しい方法であるかどうかはわかりません。

私の最終目標は単純です。@ Userオブジェクトに、ActiveDirectoryを介して入力される追加のプロパティを持たせたいです。あなたが提供できるどんな助けにも感謝します。

13
Mike

あなたの既存の質問を見たとき、私はこの問題で他の人を助けるために私の解決策でStackOverflowに自分の質問を追加しようとしていました。これは非常に一般的なことのように思われますが、それを行う方法に関する情報は複数のソースに分散しており、追跡するのは困難です。完全なリソースは1つだけではないので、これがあなたや他の人に役立つことを願っています。

これを行う最良の方法は、UserPrincipal拡張機能を使用することです。基本的に、System.DirectoryServices.AccountManagementからUserPrincipalをサブクラス化し、独自の追加プロパティを追加します。これは、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);
    } 
}

クラスの2つの属性は、ADのインスタンスに合わせてカスタマイズする必要があります。 DirectoryRdnPrefixの値はADのRDN(相対識別名)である必要があり、DirectoryObjectClassの値はuserObjectクラスのADのディレクトリオブジェクトタイプ名である必要があります。一般的なADドメインサービスのセットアップでは、両方とも上記のコードで使用されているとおりである必要がありますが、LDSのセットアップでは、異なる可能性があります。組織で使用する2つの新しいプロパティ、「title」と「department」を追加しました。それから、好きな他のプロパティを追加する方法のアイデアを得ることができます。基本的には、ここで提供したテンプレートを使用してプロパティを作成するだけです。プロパティには任意の名前を付けることができますが、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に慣れていない場合は、GivenNameSurnameDisplayNameなどのいくつかのユーザープロパティが組み込まれています。特にあなたの状況では、電話とメールについて具体的に言及したので、VoiceTelephoneNumberEmailAddressがあります。完全なリストは MSDN docs で確認できます。組み込み情報だけが必要な場合は、上で示したようにUserPrincipalを拡張する必要はありません。あなたはただするでしょう:

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

ただし、10回のうち9回は組み込みでは不十分なので、残りを簡単に取得する方法を知っておくとよいでしょう。

最後に、これを使用するビューに@using行を追加する必要がなかったので、先に進み、Viewsフォルダーのweb.configに名前空間を追加しました。この部分は重要です。プロジェクト(およびエリアを使用している場合は各エリアの個々のViewsフォルダー)ではなく、Viewsフォルダーのweb.configに追加する必要があります。

<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>
29
Chris Pratt