You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java中使用‘run as’动词请求UAC权限提升

Java实现run as提权修改网络配置

我完全理解你的需求:你的Java程序修改网卡配置时需要管理员权限,报错提示需要提升权限,你想要像Python那样通过run as动词调用ShellExecute来重启程序并获取权限,同时排除快捷方式、未解释的JNA/wizmo方案。下面是针对你场景的具体实现:

前置准备:引入JNA依赖

Java本身没有直接调用Windows API的能力,所以我们需要用**JNA(Java Native Access)**来调用IsUserAnAdmin和ShellExecuteW两个Windows原生API。这里明确告诉你怎么引入依赖:

如果用Maven项目

在你的pom.xml中添加以下依赖:

<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna</artifactId>
    <version>5.13.0</version>
</dependency>
<dependency>
    <groupId>net.java.dev.jna</groupId>
    <artifactId>jna-platform</artifactId>
    <version>5.13.0</version>
</dependency>

如果是普通Java项目

从JNA官方发布渠道下载jna-5.13.0.jar和jna-platform-5.13.0.jar,添加到项目的类路径中即可。

完整实现代码

下面的代码整合了权限检查、提权重启、网络配置命令执行三个功能,完全适配你的场景:

import com.sun.jna.Native;
import com.sun.jna.platform.win32.Shell32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.win32.W32APIOptions;

public class NetworkConfigAdmin {

    // 扩展Shell32接口,添加我们需要的Windows API方法
    public interface Shell32Ext extends Shell32 {
        // 加载shell32.dll并实例化接口
        Shell32Ext INSTANCE = Native.load("shell32", Shell32Ext.class, W32APIOptions.DEFAULT_OPTIONS);
        
        // 检查当前用户是否拥有管理员权限
        boolean IsUserAnAdmin();
        
        // 调用ShellExecuteW执行程序,支持run as动词
        WinDef.HINSTANCE ShellExecuteW(WinDef.HWND hwnd, String lpOperation, String lpFile, String lpParameters, String lpDirectory, int nShowCmd);
    }

    public static void main(String[] args) {
        // 第一步:检查当前进程是否已经是管理员权限
        if (!Shell32Ext.INSTANCE.IsUserAnAdmin()) {
            // 如果不是,以管理员身份重启当前程序
            restartAsAdmin();
            return; // 原进程退出,等待提权后的新进程执行
        }

        // 第二步:已经获得管理员权限,执行网络配置命令
        String setIpCommand = "netsh interface ip set address name=\"Ethernet\" static 192.168.0.4 255.255.255.0 192.168.0.1 1";
        String setDnsCommand = "netsh interface ipv4 add dnsserver \"Ethernet\" address=192.168.0.1 index=1";
        
        runCommand(setIpCommand);
        runCommand(setDnsCommand);
        System.out.println("以太网IP和DNS配置修改完成!");
    }

    /**
     * 以管理员身份重启当前Java程序
     */
    private static void restartAsAdmin() {
        try {
            // 获取Java运行时的路径(javaw.exe,避免弹出控制台窗口)
            String javaRuntimePath = System.getProperty("java.home") + "\\bin\\javaw.exe";
            
            // 获取当前程序的执行路径(类文件或JAR包)
            String programPath = NetworkConfigAdmin.class.getProtectionDomain().getCodeSource().getLocation().getPath();
            // 解码URL编码的路径(比如空格会被转成%20)
            programPath = java.net.URLDecoder.decode(programPath, "UTF-8");
            
            // 构造启动参数:如果是JAR包用-jar,否则用主类名
            String startupParams;
            if (programPath.endsWith(".jar")) {
                startupParams = "-jar \"" + programPath + "\"";
            } else {
                startupParams = NetworkConfigAdmin.class.getCanonicalName();
            }

            // 调用ShellExecuteW,传入run as动词触发UAC权限提升
            // 参数说明:
            // hwnd: 窗口句柄,传null即可
            // lpOperation: 操作动词,这里用"run as"
            // lpFile: 要执行的程序路径(javaw.exe)
            // lpParameters: 启动参数
            // lpDirectory: 工作目录,传null用当前目录
            // nShowCmd: 窗口显示方式,1代表正常显示
            Shell32Ext.INSTANCE.ShellExecuteW(null, "runas", javaRuntimePath, startupParams, null, 1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 执行系统命令,继承输出和错误流到控制台
     */
    private static void runCommand(String command) {
        try {
            // 用cmd.exe /c执行命令,避免带引号参数的拆分问题
            ProcessBuilder processBuilder = new ProcessBuilder("cmd.exe", "/c", command);
            // 将命令的输出和错误流重定向到当前控制台
            processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT);
            processBuilder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
            // 等待命令执行完成,确保配置生效
            processBuilder.start().waitFor();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

代码关键部分解释

  1. Shell32Ext接口:我们扩展了JNA自带的Shell32接口,添加了IsUserAnAdmin(检查权限)和ShellExecuteW(提权启动程序)两个方法,直接调用Windows原生API,没有黑箱操作。
  2. 权限检查逻辑:在main方法开头先判断是否有管理员权限,如果没有就调用restartAsAdmin重启程序,原进程直接退出。
  3. 提权重启逻辑:restartAsAdmin方法中,我们获取当前Java运行时的路径和程序本身的路径,然后用ShellExecuteW传递run as动词,系统会自动弹出UAC权限提示框,用户点击允许后,新的进程就会以管理员身份运行。
  4. 命令执行优化:原来的runCommand方法改成用cmd.exe /c执行命令,这样能正确处理带引号的参数(比如name="Ethernet"),同时添加waitFor()确保命令执行完成后再继续。

使用注意事项

  • 如果你是直接运行类文件(不是打包成JAR),要确保你的项目类路径配置正确,否则getCodeSource().getLocation()可能无法正确获取到类文件路径。
  • 弹出UAC提示后,必须点击“允许”才能继续执行网络配置操作。
  • 测试时可以先运行程序,确认会弹出UAC提示,提权后能正常修改IP和DNS。

内容的提问来源于stack exchange,提问作者Hrvoje T

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:25:22