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

如何使用Java调用Azure AD的AWS单账户访问企业应用?

解决Java程序化获取Azure AD SAML断言用于AWS SSO

核心思路

要程序化实现Azure AD认证并获取SAML断言,本质是模拟Azure AD的OAuth2授权流程,获取包含SAML断言的响应——因为针对AWS企业应用的SSO配置,Azure AD会在授权成功后返回SAML断言作为access_token的内容。

步骤1:准备Azure AD配置参数

先从Azure AD门户提取以下关键参数:

  • tenant-id: Azure AD租户ID
  • client-id: AWS单账户访问企业应用的客户端ID
  • client-secret: 企业应用的客户端密钥
  • redirect-uri: 已在Azure AD应用中配置的重定向地址(授权码流程用,比如http://localhost:8080/callback)
  • resource: AWS应用的标识符,固定为https://signin.aws.amazon.com/saml

步骤2:选择适合的认证流程

根据场景需求,可选两种主流实现方式:

方式一:授权码流程(需用户交互)

适合需要用户手动登录的场景,流程为:引导用户登录获取授权码 → 用授权码交换令牌和SAML断言。

代码示例

import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class AzureAdSamlClient {
    private static final String TENANT_ID = "你的租户ID";
    private static final String CLIENT_ID = "你的客户端ID";
    private static final String CLIENT_SECRET = "你的客户端密钥";
    private static final String REDIRECT_URI = "http://localhost:8080/callback";
    private static final String RESOURCE = "https://signin.aws.amazon.com/saml";

    public static void main(String[] args) throws Exception {
        // 1. 生成授权登录URL,引导用户获取授权码
        String authUrl = String.format(
            "https://login.microsoftonline.com/%s/oauth2/authorize?client_id=%s&response_type=code&redirect_uri=%s&resource=%s&response_mode=query",
            TENANT_ID, CLIENT_ID, REDIRECT_URI, RESOURCE
        );
        System.out.println("访问以下URL登录并复制回调中的code参数:");
        System.out.println(authUrl);

        // 2. 替换为用户实际获取的授权码
        String authCode = "用户登录后得到的code";

        // 3. 用授权码交换SAML断言
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPost tokenPost = new HttpPost(String.format("https://login.microsoftonline.com/%s/oauth2/token", TENANT_ID));
            String body = String.format(
                "grant_type=authorization_code&client_id=%s&client_secret=%s&code=%s&redirect_uri=%s&resource=%s",
                CLIENT_ID, CLIENT_SECRET, authCode, REDIRECT_URI, RESOURCE
            );
            tokenPost.setEntity(new StringEntity(body));
            tokenPost.setHeader("Content-Type", "application/x-www-form-urlencoded");

            String response = EntityUtils.toString(httpClient.execute(tokenPost).getEntity());
            ObjectMapper mapper = new ObjectMapper();
            JsonNode jsonNode = mapper.readTree(response);

            // 提取Base64编码的SAML断言
            String samlAssertion = jsonNode.get("access_token").asText();
            System.out.println("\n获取到的SAML断言:");
            System.out.println(samlAssertion);
        }
    }
}

方式二:客户端凭证流程(无用户交互)

适合后台服务自动执行的场景,无需用户登录,但需确保Azure AD企业应用已配置对应权限并授予管理员同意。

代码示例

import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class AzureAdSamlClient {
    private static final String TENANT_ID = "你的租户ID";
    private static final String CLIENT_ID = "你的客户端ID";
    private static final String CLIENT_SECRET = "你的客户端密钥";
    private static final String RESOURCE = "https://signin.aws.amazon.com/saml";

    public static void main(String[] args) throws Exception {
        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
            HttpPost tokenPost = new HttpPost(String.format("https://login.microsoftonline.com/%s/oauth2/token", TENANT_ID));
            String body = String.format(
                "grant_type=client_credentials&client_id=%s&client_secret=%s&resource=%s",
                CLIENT_ID, CLIENT_SECRET, RESOURCE
            );
            tokenPost.setEntity(new StringEntity(body));
            tokenPost.setHeader("Content-Type", "application/x-www-form-urlencoded");

            String response = EntityUtils.toString(httpClient.execute(tokenPost).getEntity());
            ObjectMapper mapper = new ObjectMapper();
            JsonNode jsonNode = mapper.readTree(response);

            String samlAssertion = jsonNode.get("access_token").asText();
            System.out.println("获取到的SAML断言:");
            System.out.println(samlAssertion);
        }
    }
}

关键注意事项

  • 授权码流程必须确保Azure AD应用中已配置对应的redirect-uri,否则授权码交换会失败。
  • 客户端凭证流程需在Azure AD应用的API权限中添加对AWS应用的权限,并完成管理员同意操作。
  • 获取到的access_token即为Base64编码的SAML断言,可直接用于调用AWS STS的AssumeRoleWithSAML接口完成角色切换。
  • 推荐使用微软官方的MSAL4J库简化流程,避免手动处理HTTP请求的细节。

使用MSAL4J简化实现(推荐)

MSAL4J是微软官方Java认证库,能更安全高效地处理Azure AD认证流程:

Maven依赖

<dependency>
    <groupId>com.microsoft.azure</groupId>
    <artifactId>msal4j</artifactId>
    <version>1.23.0</version>
</dependency>

授权码流程示例

import com.microsoft.aad.msal4j.*;
import java.net.URI;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;

public class MsalSamlExample {
    private static final String TENANT_ID = "你的租户ID";
    private static final String CLIENT_ID = "你的客户端ID";
    private static final String CLIENT_SECRET = "你的客户端密钥";
    private static final String REDIRECT_URI = "http://localhost:8080/callback";
    private static final String RESOURCE = "https://signin.aws.amazon.com/saml";

    public static void main(String[] args) throws Exception {
        // 构造客户端实例
        ConfidentialClientApplication app = ConfidentialClientApplication.builder(
                CLIENT_ID, ClientCredentialFactory.createFromSecret(CLIENT_SECRET))
                .authority(String.format("https://login.microsoftonline.com/%s", TENANT_ID))
                .build();

        // 生成授权登录URL
        AuthorizationRequestUrlParameters authParams = AuthorizationRequestUrlParameters.builder(
                new URI(REDIRECT_URI), Collections.singleton(RESOURCE))
                .responseMode(ResponseMode.QUERY)
                .build();
        String authUrl = app.getAuthorizationRequestUrl(authParams).toString();
        System.out.println("访问以下URL登录并复制code参数:");
        System.out.println(authUrl);

        // 替换为实际授权码
        String authCode = "用户获取的code";

        // 交换令牌获取SAML断言
        CompletableFuture<IAuthenticationResult> future = app.acquireToken(AuthorizationCodeParameters.builder(
                authCode, new URI(REDIRECT_URI)).build());
        IAuthenticationResult result = future.get();

        String samlAssertion = result.accessToken();
        System.out.println("\nSAML断言:");
        System.out.println(samlAssertion);
    }
}

客户端凭证流程示例

import com.microsoft.aad.msal4j.*;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;

public class MsalClientCredentialExample {
    private static final String TENANT_ID = "你的租户ID";
    private static final String CLIENT_ID = "你的客户端ID";
    private static final String CLIENT_SECRET = "你的客户端密钥";
    private static final String RESOURCE = "https://signin.aws.amazon.com/saml";

    public static void main(String[] args) throws Exception {
        ConfidentialClientApplication app = ConfidentialClientApplication.builder(
                CLIENT_ID, ClientCredentialFactory.createFromSecret(CLIENT_SECRET))
                .authority(String.format("https://login.microsoftonline.com/%s", TENANT_ID))
                .build();

        ClientCredentialParameters params = ClientCredentialParameters.builder(
                Collections.singleton(RESOURCE))
                .build();

        CompletableFuture<IAuthenticationResult> future = app.acquireToken(params);
        IAuthenticationResult result = future.get();

        String samlAssertion = result.accessToken();
        System.out.println("SAML断言:");
        System.out.println(samlAssertion);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 16:50:31