8

アプリケーションでNTLM認証を使用して、ユーザーが特定の操作を実行できるかどうかを判断します。(WinFormsアプリケーションで)現在のWindowsログインのIPrincipalを使用し、IsInRoleを呼び出して特定のグループメンバーシップを確認します。

ユーザーがマシンのローカル管理者であることを確認するには、次を使用します。

AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
...
bool allowed = Thread.CurrentPrincipal.IsInRole(@"Builtin\Administrators")

これは、現在のユーザーがAdministratorユーザーであるか、グループのメンバーである別のユーザーである場合に機能しますBuiltin\Administrators

Windows 7でのテストでは、これが期待どおりに機能しなくなっていることがわかりました。ユーザーはAdministrator引き続き正常に機能しますが、グループのメンバーである他のユーザーは、呼び出しBuiltin\Administratorsに対してfalseを返します。IsInRole

この違いの原因は何でしょうか?デフォルト設定がどこかで変更されたように感じますが(gpeditで可能)、原因のように見えるものは見つかりません。

4

5 に答える 5

9

問題は、Windows セキュリティ (別名「UAC」) が邪魔をしていることです。管理者の役割には特別な処理があり、昇格するまでユーザーは実際にはこれらの役割を持ちません。管理者の役割は、ある意味で「ゴースト化」されています。存在しますが、アクセス許可のチェックや (簡単に) 存在をテストすることさえできません。http://msdn.microsoft.com/en-us/library/46ks97y7.aspxのメモを参照して ください。

これは、必要な回避策を実行するサンプル コードを使用して、この問題について説明するシリーズです。

独自の UAC プロンプトを作成し、名前とパスワードを使用して Win32 ログオン API を呼び出すことで、ASP.NET アプリで同様の問題を解決しました。幸運にも .NET デスクトップ アプリを使用できる場合があります。その場合は、通常の昇格要求を使用できます。

昇格せずに管理者権限を確認する C# コードを次に示します。

    public const UInt32 TOKEN_DUPLICATE = 0x0002;
    public const UInt32 TOKEN_IMPERSONATE = 0x0004;
    public const UInt32 TOKEN_QUERY = 0x0008;

    public enum TOKEN_ELEVATION_TYPE
    {
        TokenElevationTypeDefault = 1,
        TokenElevationTypeFull,
        TokenElevationTypeLimited
    }

    public enum TOKEN_INFORMATION_CLASS
    {
        TokenUser = 1,
        TokenGroups,
        TokenPrivileges,
        TokenOwner,
        TokenPrimaryGroup,
        TokenDefaultDacl,
        TokenSource,
        TokenType,
        TokenImpersonationLevel,
        TokenStatistics,
        TokenRestrictedSids,
        TokenSessionId,
        TokenGroupsAndPrivileges,
        TokenSessionReference,
        TokenSandBoxInert,
        TokenAuditPolicy,
        TokenOrigin,
        TokenElevationType,
        TokenLinkedToken,
        TokenElevation,
        TokenHasRestrictions,
        TokenAccessInformation,
        TokenVirtualizationAllowed,
        TokenVirtualizationEnabled,
        TokenIntegrityLevel,
        TokenUIAccess,
        TokenMandatoryPolicy,
        TokenLogonSid,
        MaxTokenInfoClass  // MaxTokenInfoClass should always be the last enum 
    }

    public enum SECURITY_IMPERSONATION_LEVEL
    {
        SecurityAnonymous,
        SecurityIdentification,
        SecurityImpersonation,
        SecurityDelegation
    }


    public static bool IsAdmin()
    {
        var identity = WindowsIdentity.GetCurrent();
        return (null != identity && new WindowsPrincipal(identity).IsInRole(WindowsBuiltInRole.Administrator));
    }

    /// <summary>
    /// The function checks whether the primary access token of the process belongs
    /// to user account that is a member of the local Administrators group, even if
    /// it currently is not elevated.
    /// </summary>
    /// <returns>
    /// Returns true if the primary access token of the process belongs to user
    /// account that is a member of the local Administrators group. Returns false
    /// if the token does not.
    /// </returns>
    public static bool CanBeAdmin()
    {
        bool fInAdminGroup = false;
        IntPtr hToken = IntPtr.Zero;
        IntPtr hTokenToCheck = IntPtr.Zero;
        IntPtr pElevationType = IntPtr.Zero;
        IntPtr pLinkedToken = IntPtr.Zero;
        int cbSize = 0;

        if (IsAdmin())
            return true;

        try
        {
            // Check the token for this user
            hToken = WindowsIdentity.GetCurrent().Token;

            // Determine whether system is running Windows Vista or later operating
            // systems (major version >= 6) because they support linked tokens, but
            // previous versions (major version < 6) do not.
            if (Environment.OSVersion.Version.Major >= 6)
            {
                // Running Windows Vista or later (major version >= 6).
                // Determine token type: limited, elevated, or default.

                // Allocate a buffer for the elevation type information.
                cbSize = sizeof(TOKEN_ELEVATION_TYPE);
                pElevationType = Marshal.AllocHGlobal(cbSize);
                if (pElevationType == IntPtr.Zero)
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                // Retrieve token elevation type information.
                if (!GetTokenInformation(hToken,
                    TOKEN_INFORMATION_CLASS.TokenElevationType, pElevationType, cbSize, out cbSize))
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }

                // Marshal the TOKEN_ELEVATION_TYPE enum from native to .NET.
                TOKEN_ELEVATION_TYPE elevType = (TOKEN_ELEVATION_TYPE)Marshal.ReadInt32(pElevationType);

                // If limited, get the linked elevated token for further check.
                if (elevType == TOKEN_ELEVATION_TYPE.TokenElevationTypeLimited)
                {
                    // Allocate a buffer for the linked token.
                    cbSize = IntPtr.Size;
                    pLinkedToken = Marshal.AllocHGlobal(cbSize);
                    if (pLinkedToken == IntPtr.Zero)
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }

                    // Get the linked token.
                    if (!GetTokenInformation(hToken,
                        TOKEN_INFORMATION_CLASS.TokenLinkedToken, pLinkedToken,
                        cbSize, out cbSize))
                    {
                        throw new Win32Exception(Marshal.GetLastWin32Error());
                    }

                    // Marshal the linked token value from native to .NET.
                    hTokenToCheck = Marshal.ReadIntPtr(pLinkedToken);
                }
            }

            // CheckTokenMembership requires an impersonation token. If we just got
            // a linked token, it already is an impersonation token.  If we did not
            // get a linked token, duplicate the original into an impersonation
            // token for CheckTokenMembership.
            if (hTokenToCheck == IntPtr.Zero)
            {
                if (!DuplicateToken(hToken, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, ref hTokenToCheck))
                {
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                }
            }

            // Check if the token to be checked contains admin SID.
            WindowsIdentity id = new WindowsIdentity(hTokenToCheck);
            WindowsPrincipal principal = new WindowsPrincipal(id);
            fInAdminGroup = principal.IsInRole(WindowsBuiltInRole.Administrator);
        }
        catch
        {
            return false;
        }
        finally
        {
            // Centralized cleanup for all allocated resources.
            if (pElevationType != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(pElevationType);
                pElevationType = IntPtr.Zero;
            }
            if (pLinkedToken != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(pLinkedToken);
                pLinkedToken = IntPtr.Zero;
            }
        }

        return fInAdminGroup;
    }

どこかでオンラインで見つけた記事から改作されています。申し訳ありませんが、帰属を失いました。

于 2010-04-20T18:35:37.210 に答える
7

これは私にとってはうまくいきました-必要なのは、プログラムが管理者の役割で開始されたかどうかを確認することだけでした:

   public static bool IsAdminRole()
    {
        AppDomain domain = Thread.GetDomain();

        domain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
        WindowsPrincipal principle = (WindowsPrincipal)Thread.CurrentPrincipal;
        return principle.IsInRole(WindowsBuiltInRole.Administrator);
    }

誰かが役に立つものを見つけてくれることを願っています!

マイク

于 2011-05-04T12:50:40.737 に答える
3

これに別の方法で取り組むstackoverflowに関する別の記事を見つけました。私はそれを以下の方法に適応させました。Windows 7 を使用すると、「管理者として実行」すると、管理者には true、非管理者には false、非管理者には true が返されました。これは、MSDN で PrincipleContext クラスを一目見ただけで、.Net 3.5 および XP SP2 以降でのみ機能するようです。

private static bool IsUserAdmin()
{
    bool isAdmin = false;

    WindowsIdentity wi = WindowsIdentity.GetCurrent();
    WindowsPrincipal wp = new WindowsPrincipal(wi);
    isAdmin = wp.IsInRole(WindowsBuiltInRole.Administrator);

    Console.WriteLine(isAdmin); // False for Windows 7 even if user is admin

    //found the code below at [http://stackoverflow.com/questions/1089046/in-net-c-test-if-user-is-an-administrative-user][1]  

    // Add reference to System.DirectoryServices.AccountManagement (Add Referemce -> .Net)
    // Add using System.DirectoryServices.AccountManagement;

    if (!isAdmin) //PrincipleContext takes a couple seconds, so I don't use it if not necessary
    {
        using (PrincipalContext pc = new PrincipalContext(ContextType.Machine, null))
        {
            UserPrincipal up = UserPrincipal.Current;
            GroupPrincipal gp = GroupPrincipal.FindByIdentity(pc, "Administrators");
            if (up.IsMemberOf(gp))
            {
                isAdmin = true;
            }
        }
    }
    Console.WriteLine(isAdmin); // True for Windows 7 if user is admin


    return isAdmin;
}
于 2011-08-13T22:57:35.337 に答える
1

アプリケーションが昇格されていません。通常の状況では、UAC はユーザーの「管理者らしさ」を取り除きます。アプリを管理者のみが使用できる場合は、アプリを昇格させるマニフェストを追加して、管理者としての資格を維持できるようにします。いずれかで使用できる場合、昇格マニフェストのある部分とない部分の 2 つの部分に分割し、シールドで装飾されたボタンまたはメニュー項目から昇格した部分を起動して、ユーザーがクリックしないようにすることをお勧めします。彼らが管理者でない場合。(古い OS では、ボタンにシールドを配置するメッセージは無視されます。) 「UAC」、「partition」、および「shellexecute」で検索すると役立ちます。

于 2010-04-20T18:48:36.767 に答える
0

私は DavB.cs と同じアプローチを使用しました: http://tieledeclercq.blogspot.be/2013/09/c-is-this-valid-administrator-that-c ​​an.html

いくつかの違いがあります:

  1. 管理者は、ローカル管理者グループのネストされたメンバーである可能性があります。
  2. (現在のユーザーとしてではなく)外部資格情報を使用する必要がありました。
于 2013-09-25T12:43:24.087 に答える