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

如何在不开启允许公共客户端流的情况下实现Azure AD委托权限认证

问题描述

我有一个名为Azure_AD_Delegated的Azure AD应用,已配置User.Read.All和GroupMember.Read.All的委托权限,采用用户名密码(ROPC)认证方式,核心代码如下:

new UsernamePasswordCredentialBuilder()
    .clientId(clientId)
    .username(username)
    .password(password)
    .tenantId(tenantId)
    .build()
    .getTokenSync(tokenRequestContext.addScopes(".default"));

未开启应用的「允许公共客户端流」选项时,执行代码会抛出异常:

com.microsoft.aad.msal4j.MsalServiceException: AADSTS7000218: The request body must contain the following parameter: 'client_assertion' or 'client_secret'. Trace ID: 32eeb109-2202-443c-9a5d-56606bba0e00 Correlation ID: ab8a7cea-ee9c-4ba6-8b3d-23faaef98e94 Timestamp: 2024-05-17 13:00:05Z

开启「允许公共客户端流」后认证成功,可正常调用Graph API,但微软文档提示该选项存在安全风险,且客户不愿使用应用权限+客户端凭证流。需要实现不开启公共客户端流的前提下,用用户名密码认证调用Graph API。

完整的可运行代码如下:

private void generateAccessTokenByUserNameAndPassword() {
    
    try {
        
        TokenRequestContext tokenRequestContext = new TokenRequestContext();
        accessToken = new UsernamePasswordCredentialBuilder()
                .clientId(clientId)
                .username(username)
                .password(password)
                .tenantId(tenantId)
                .build()
                .getTokenSync(tokenRequestContext.addScopes(".default"));
        
        graphClient = getGraphClient();
        
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    
}


@SuppressWarnings("rawtypes")
private GraphServiceClient getGraphClient() {
    
    IAuthenticationProvider provider = new IAuthenticationProvider() {

        @Override
        public CompletableFuture<String> getAuthorizationTokenAsync(URL requestUrl) {
            return CompletableFuture.completedFuture(accessToken.getToken());
        }
    };
    return GraphServiceClient.builder().authenticationProvider(provider).buildClient();
}

解决方案

原理说明

当应用未开启「允许公共客户端流」时,Azure AD将其视为机密客户端,要求所有认证请求必须携带客户端身份凭证(client_secret或客户端证书)以验证应用合法性,这是规避公共客户端安全风险的核心机制。用户名密码(ROPC)流同样支持机密客户端模式,只需在请求中添加客户端凭证即可。

具体步骤

  1. 生成客户端密钥:在Azure AD应用的「证书和密码」页面,新建客户端密码(client secret),记录密钥值(仅生成时可见,需妥善保存)。
  2. 修改认证代码:在UsernamePasswordCredentialBuilder中添加.clientSecret(clientSecret)配置,将客户端密钥传入认证流程。

修改后的代码示例

private void generateAccessTokenByUserNameAndPassword() {
    
    try {
        // 替换为你的客户端密钥
        String clientSecret = "YOUR_CLIENT_SECRET_VALUE";
        
        TokenRequestContext tokenRequestContext = new TokenRequestContext();
        accessToken = new UsernamePasswordCredentialBuilder()
                .clientId(clientId)
                .username(username)
                .password(password)
                .tenantId(tenantId)
                // 添加客户端密钥,满足机密客户端的身份验证要求
                .clientSecret(clientSecret)
                .build()
                .getTokenSync(tokenRequestContext.addScopes(".default"));
        
        graphClient = getGraphClient();
        
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    
}

// getGraphClient方法保持不变
@SuppressWarnings("rawtypes")
private GraphServiceClient getGraphClient() {
    
    IAuthenticationProvider provider = new IAuthenticationProvider() {

        @Override
        public CompletableFuture<String> getAuthorizationTokenAsync(URL requestUrl) {
            return CompletableFuture.completedFuture(accessToken.getToken());
        }
    };
    return GraphServiceClient.builder().authenticationProvider(provider).buildClient();
}

注意事项

  • 客户端密钥属于敏感信息,需通过安全方式存储(如Azure Key Vault),禁止硬编码在代码中。
  • 若需更高安全性,可使用客户端证书替代客户端密钥,只需将.clientSecret(clientSecret)替换为.clientCertificate(clientCertificate)(需提前在Azure AD应用中配置证书)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 18:00:56