检测 Java 应用程序是不是以 Windows 管理员身份运行

Posted

技术标签:

【中文标题】检测 Java 应用程序是不是以 Windows 管理员身份运行【英文标题】:Detect if Java application was run as a Windows admin检测 Java 应用程序是否以 Windows 管理员身份运行 【发布时间】:2011-05-20 00:27:03 【问题描述】:

我有一个 Java 应用程序。无论如何我可以判断该进程是否在 Windows 7 上以管理员权限运行。

【问题讨论】:

我在 Linux 中测试了我的答案。它可能不依赖于操作系统,但我不知道。 【参考方案1】:

Java 运行时环境中没有这样的工具,但可能在依赖于平台的本机例程中。请注意,通常最好的确定方法是实际尝试去做,看看它是否失败。

【讨论】:

【参考方案2】:

仅通过尝试需要此类访问的操作(如绑定低编号端口,或打开已知受保护的文件)。

【讨论】:

谢谢。这对我有用。我试图在程序文件中创建一个测试文件并捕获 IOException (Access is Denied)... new File(System.getenv("programfiles")+"/test.tst").createNewFile()【参考方案3】:

或者你可以这样做:

System.getenv().get("USER")

并查看哪个用户启动了该过程。

当我以我的身份运行它时,我得到“goran”,当我使用 sudo 运行它时,我得到“root”。在 Linux 上工作。 可能需要什么。

【讨论】:

嗯,这很有趣,让我试试这个,看看它在 Windows 上的作用。如果它说“管理员”,这将起作用。 请发布您的结果。我真的很想知道这是否与操作系统无关 在 Windows 7 上,如果我运行此代码,我会得到一个空值。但是,如果我运行 System.getProperty("user.name"),我会得到我的用户名。但是,这仍然不能说明我是否是管理员。 有趣。尝试获取所有属性:System.out.println(System.getenv()); 也许,还有别的东西。 也可以试试:System.out.println(System.getProperties());【参考方案4】:

我在网上找到了这个代码 sn-p,我认为它会为你完成这项工作。

public static boolean isAdmin() 
    String groups[] = (new com.sun.security.auth.module.NTSystem()).getGroupIDs();
    for (String group : groups) 
        if (group.equals("S-1-5-32-544"))
            return true;
    
    return false;

它仅适用于 Windows,并内置于核心 Java 包中。我刚刚测试了这段代码,它确实有效。这让我感到惊讶,但确实如此。

SID S-1-5-32-544 是 Windows 操作系统中管理员组的 ID。

Here is the link 了解其工作原理的更多详细信息。

【讨论】:

不错的 S-1-5-32-544。我早该想到的。 ... 由于私有类,仅适用于 Sun JVM。 请注意,此 sn-p 测试活动用户是否为管理员,而不是用户是否已将应用程序作为提升的进程启动! 如果应用程序以管理员帐户的正常权限运行,这将不起作用。仍然返回 true... 此代码可能仅适用于 Oracle JRE,不保证适用于 JRE 的任何更新:oracle.com/technetwork/java/faq-sun-packages-142232.html【参考方案5】:

答案中标记为最佳的方法对我来说效果很好,直到我不得不在 Linux 机器上在 Jenkins 中构建代码。 com.sun.security.auth.module.NTSystem() 在那里不可用,使用 sun 包通常被认为是一种不好的做法: link

【讨论】:

从您的 Windows 机器中获取“rt.jar”。将它添加到 Linux 机器上的类路径中。然后在你的应用程序中有代码,可以查看它是否是 Windows PC,执行接受的答案,如果是 Linux,运行这个问题的 Linux 答案。想到的第一个解决方案。对我来说,我只需要在 Windows 上这样做,所以我没有这个问题。它是 Java 做的很糟糕的事情之一。只是一个旁注,您应该将其添加为评论。 感谢有关 rt.jar 的提示!我会试一试。 PS:我知道,这应该是一个评论,但不幸的是,由于***授予权限的方式有点奇怪,以我目前的声誉,我只能评论我自己的答案/问题=)【参考方案6】:

我找到了一个似乎与平台无关的不同解决方案。它尝试编写系统首选项。如果失败,用户可能不是管理员。

正如Tomáš Zato 建议的那样,您可能希望抑制由此方法引起的错误消息。你可以通过设置System.err来做到这一点:

import java.io.OutputStream;
import java.io.PrintStream;
import java.util.prefs.Preferences;

import static java.lang.System.setErr;
import static java.util.prefs.Preferences.systemRoot;

public class AdministratorChecker

    public static final boolean IS_RUNNING_AS_ADMINISTRATOR;

    static
    
        IS_RUNNING_AS_ADMINISTRATOR = isRunningAsAdministrator();
    

    private static boolean isRunningAsAdministrator()
    
        Preferences preferences = systemRoot();

        synchronized (System.err)
        
            setErr(new PrintStream(new OutputStream()
            
                @Override
                public void write(int b)
                
                
            ));

            try
            
                preferences.put("foo", "bar"); // SecurityException on Windows
                preferences.remove("foo");
                preferences.flush(); // BackingStoreException on Linux
                return true;
             catch (Exception exception)
            
                return false;
             finally
            
                setErr(System.err);
            
        
    

【讨论】:

很好,但我建议您将状态缓存到私有静态变量中。它不会在程序的一个实例中改变。 还有一件事——函数不断产生输出,例如Kvě 07, 2015 1:49:14 ODP. java.util.prefs.WindowsPreferences <init> WARNING: Could not open/create prefs root node Software\JavaSoft\Prefs at root 0x80000002. Windows RegCreateKeyEx(...) returned error code 5. 是否可以抑制这些? @TomášZato 我改进了我的答案 请注意,由于System.setErr(null),答案中的第二个代码块会抛出NullPointerException。要解决此问题,请改用虚拟输出流:System.setErr(new PrintStream(new OutputStream() @Override public void write(int i) throws IOException )); 如果其他线程也没有同步到System.err,则synchronized(systemErr) 行无效。【参考方案7】:

这是一个在 Windows 10 上的解决方案,我猜它在其他 Windows 操作系统上也能正常运行。

public static boolean isAdmin() 
    try 
        ProcessBuilder processBuilder = new ProcessBuilder("cmd.exe");
        Process process = processBuilder.start();
        PrintStream printStream = new PrintStream(process.getOutputStream(), true);
        Scanner scanner = new Scanner(process.getInputStream());
        printStream.println("@echo off");
        printStream.println(">nul 2>&1 \"%SYSTEMROOT%\\system32\\cacls.exe\" \"%SYSTEMROOT%\\system32\\config\\system\"");
        printStream.println("echo %errorlevel%");

        boolean printedErrorlevel = false;
        while (true) 
            String nextLine = scanner.nextLine();
            if (printedErrorlevel) 
                int errorlevel = Integer.parseInt(nextLine);
                return errorlevel == 0;
             else if (nextLine.equals("echo %errorlevel%")) 
                printedErrorlevel = true;
            
        
     catch (IOException e) 
        return false;
    

【讨论】:

【参考方案8】:

以下代码适合我

命令提示符命令

net user

Java 代码

public static  boolean isAdmin() 
        StringBuilder outputbuilder = new StringBuilder();
    try 
        ProcessBuilder builder = new ProcessBuilder(
                "cmd.exe","/c" ,"net user");
        builder.redirectErrorStream(true);
        Process p = builder.start();
        BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
        String line;
        while (true) 
            line = r.readLine();
            if (line == null)  break; 
            outputbuilder.append(line);
        
     catch (IOException e) 
        e.printStackTrace();
        return false;
    
    System.out.println(outputbuilder.toString());
    return outputbuilder.toString().contains("Administrator");

【讨论】:

以上是关于检测 Java 应用程序是不是以 Windows 管理员身份运行的主要内容,如果未能解决你的问题,请参考以下文章

C/C++/Assembly 以编程方式检测超线程在 Windows、Mac 和 Linux 上是不是处于活动状态 [重复]

如何检测 x64 Windows 上是不是安装了 32 位 Java,仅查看文件系统和注册表?

Windows 和 Mac 在密钥检测方面的 Java 差异

如何以编程方式检测Windows Phone 8.1操作系统版本?

如何以编程方式检查 Windows 是不是是最新的?

检测 Windows 机器是不是运行病毒扫描程序? [复制]