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

Azure AD授权码流Core Java实现及无浏览器令牌获取咨询

Azure AD授权码流(Authorization Code)无浏览器交互的Core Java实现

背景

  • 已实现Azure AD的Client Credential授权类型(代码如下)
  • 需求:基于Core Java实现Authorization Code授权类型的令牌获取逻辑,要求不依赖Spring Boot,无需浏览器交互,通过代码传递凭证获取Access Token
  • 已知参数:
    • 授权URL:https://login.microsoftonline.com/{tenantID}/oauth2/v2.0/authorize
    • 令牌URL:https://login.microsoftonline.com/{tenantID}/oauth2/v2.0/token
    • Client ID:{ClientID}
    • Client Secret:{Client_Secret}
    • Scope:{ClientID}/.default
    • 回调URL:http://redirectURL
  • 已在Postman中完成令牌生成测试,咨询方案可行性及具体实现

已掌握的Client Credential实现代码

import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class AzureAdClientCredentialFlow {
    public static void main(String[] args) {
        String tenantId = "{tenantID}";
        String clientId = "CLIENT_ID";
        String clientSecret = "CLIENT_SECRET";
        String scope = clientId + "/.default";
        
        String url = String.format("https://login.microsoftonline.com/%s/oauth/v2.0/token", tenantId); 
        Map<String, String> parameters = new HashMap<>();
        parameters.put("grant_type", "client_credentials");
        parameters.put("client_id", clientId);
        parameters.put("client_secret", clientSecret);
        parameters.put("scope", scope);

        String form = parameters.keySet().stream()
                .map(key -> key + "=" + URLEncoder.encode(parameters.get(key), StandardCharsets.UTF_8))
                .collect(Collectors.joining("&"));

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder().uri(URI.create(url))
                .headers("Content-Type", "application/x-www-form-urlencoded")
                .POST(HttpRequest.BodyPublishers.ofString(form))
                .build();
        HttpResponse<?> response = null;
        try {
            response = client.send(request, HttpResponse.BodyHandlers.ofString());
            System.out.println(response.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

可行性说明

授权码流的核心是需要用户通过浏览器完成身份认证并授权,从而获取一次性的授权码(code)。要实现无浏览器交互,有两种可行路径:

  1. 预获取授权码:手动通过浏览器或Postman获取有效期内的code,再用代码调用令牌URL兑换token(code仅能使用一次)
  2. 无头浏览器模拟:使用Selenium等无头浏览器工具自动化完成登录授权流程获取code,但这需要额外依赖,不属于纯Core Java实现

如果你的场景是服务端非交互式访问,且不需要用户参与,更推荐使用Client Credential流;若必须使用授权码流,只能通过上述两种方式规避浏览器交互。

具体实现代码(Core Java)

以下是用预获取的授权码兑换Access Token的纯Core Java实现:

import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

public class AzureAdAuthorizationCodeFlow {
    public static void main(String[] args) {
        // 替换为实际参数
        String tenantId = "{tenantID}";
        String clientId = "{ClientID}";
        String clientSecret = "{Client_Secret}";
        String redirectUri = "http://redirectURL";
        String scope = clientId + "/.default";
        // 替换为预先获取的有效授权码
        String authorizationCode = "{YOUR_AUTHORIZATION_CODE}";

        String tokenUrl = String.format("https://login.microsoftonline.com/%s/oauth2/v2.0/token", tenantId);

        // 构建请求参数
        Map<String, String> parameters = new HashMap<>();
        parameters.put("grant_type", "authorization_code");
        parameters.put("client_id", clientId);
        parameters.put("client_secret", clientSecret);
        parameters.put("code", authorizationCode);
        parameters.put("redirect_uri", redirectUri);
        parameters.put("scope", scope);

        // 转换为x-www-form-urlencoded格式
        String formData = parameters.keySet().stream()
                .map(key -> key + "=" + URLEncoder.encode(parameters.get(key), StandardCharsets.UTF_8))
                .collect(Collectors.joining("&"));

        // 创建HttpClient并发送请求
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(tokenUrl))
                .header("Content-Type", "application/x-www-form-urlencoded")
                .POST(HttpRequest.BodyPublishers.ofString(formData))
                .build();

        try {
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            System.out.println("响应状态码: " + response.statusCode());
            System.out.println("响应内容: " + response.body());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

注意事项

  • 授权码(code)仅能使用一次,使用后立即失效,需重新获取
  • 授权码有效期通常为10分钟,需在有效期内完成兑换
  • 回调URL(redirect_uri)必须与Azure AD应用注册中配置的完全一致,否则会返回错误
  • 如果需要完全自动化获取code,需引入Selenium等无头浏览器依赖,实现登录授权的自动化流程

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 16:15:58