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

Java实现SharePoint Azure AD证书认证遇依赖异常求助

Java通过Azure AD证书认证访问SharePoint时遇到NoClassDefFoundError问题

我需要通过Java应用使用Azure AD证书认证访问SharePoint,已有可正常运行的C#示例代码:

using Microsoft.SharePoint.Client;
using PnP.Framework;
using System;
using System.IO;

namespace AzureADCertAuth
{
    class Program
    {
        static void Main(string[] args)
        {
            var authManager = new AuthenticationManager("00000000-0000-0000-0000-000000000000", "certpath.pfx", "password", "foo.onmicrosoft.com");
            using (var cc = authManager.GetContext("https://foo.sharepoint.com/sites/sitename"))
            {
                cc.Load(cc.Web, p => p.Title);
                cc.ExecuteQuery();
                Console.WriteLine(cc.Web.Title);
                Microsoft.SharePoint.Client.File file = cc.Web.GetFileByUrl("https://foo.sharepoint.com/sites/sitename/docpath.docx");
                ClientResult<Stream> streamResult = file.OpenBinaryStream();
                cc.ExecuteQuery();

                using (StreamReader sr = new StreamReader(streamResult.Value))
                {
                    string fileContents = sr.ReadToEnd();
                }
            }
        }
    }
}

我尝试了如下Java代码,但请求token时抛出异常:
throwIfFatal detected a jvm fatal exception, which is thrown and logged below:: java.lang.NoClassDefFoundError: io/netty/handler/codec/DefaultHeaders$ValueValidator

Java代码:

import com.azure.core.credential.AccessToken;
import com.azure.core.credential.TokenRequestContext;
import com.azure.core.http.HttpClient;
import com.azure.core.http.HttpMethod;
import com.azure.core.http.HttpRequest;
import com.azure.core.http.HttpResponse;
import com.azure.core.http.okhttp.OkHttpAsyncHttpClientBuilder;
import com.azure.identity.ClientCertificateCredential;
import com.azure.identity.ClientCertificateCredentialBuilder;

import java.net.MalformedURLException;
import java.net.URL;

public class SharepointTest {

    public static void getAccessTokenCert() {
            ClientCertificateCredential credential = new ClientCertificateCredentialBuilder().clientId(
                            "00000000-0000-0000-0000-000000000000")
                    .tenantId("11111111-1111-1111-1111-111111111111")
                    .pfxCertificate("certpath.pfx", "password")
                    .build();
            
            AccessToken token = credential.getToken(new TokenRequestContext().addScopes("https://foo.sharepoint.com/.default")).block();
            
            String url = "https://foo.sharepoint.com/sites/sitename/docpath.docx";
            HttpClient httpClient = new OkHttpAsyncHttpClientBuilder().build();

            HttpRequest request = null;
            try {
                request = new HttpRequest(HttpMethod.GET, new URL(url)).setHeader(
                        "Authorization", "Bearer " + token.getToken()).setHeader("Accept", "application/json;odata=verbose");
            }
            catch (MalformedURLException e) {
                throw new RuntimeException(e);
            }

            HttpResponse response = httpClient.send(request).block();
            String responseBody = response.getBodyAsString().block();
    }
}

请问我需要如何调整?


解决方案

1. 修复Netty依赖缺失问题

你遇到的NoClassDefFoundError是因为项目缺少Netty相关依赖包。Azure SDK依赖Netty作为默认HTTP客户端,即使使用OkHttp,部分底层组件仍需Netty支持。

Maven依赖配置

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

<!-- Azure Identity核心依赖 -->
<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-identity</artifactId>
    <version>1.12.0</version>
</dependency>
<!-- Azure Core及Netty依赖 -->
<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-core</artifactId>
    <version>1.41.0</version>
</dependency>
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.100.Final</version>
</dependency>
<!-- OkHttp客户端适配 -->
<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-core-http-okhttp</artifactId>
    <version>1.11.0</version>
</dependency>

Gradle依赖配置

在build.gradle中添加:

dependencies {
    implementation 'com.azure:azure-identity:1.12.0'
    implementation 'com.azure:azure-core:1.41.0'
    implementation 'io.netty:netty-all:4.1.100.Final'
    implementation 'com.azure:azure-core-http-okhttp:1.11.0'
}

2. 优化Java代码

除依赖问题外,代码需调整以适配SharePoint文件访问逻辑:

调整后的完整代码

import com.azure.core.credential.AccessToken;
import com.azure.core.credential.TokenRequestContext;
import com.azure.core.http.HttpClient;
import com.azure.core.http.HttpMethod;
import com.azure.core.http.HttpRequest;
import com.azure.core.http.HttpResponse;
import com.azure.core.http.okhttp.OkHttpAsyncHttpClientBuilder;
import com.azure.identity.ClientCertificateCredential;
import com.azure.identity.ClientCertificateCredentialBuilder;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

public class SharepointTest {

    public static void main(String[] args) {
        getAccessTokenCert();
    }

    public static void getAccessTokenCert() {
        // 初始化证书凭据
        ClientCertificateCredential credential = new ClientCertificateCredentialBuilder()
                .clientId("00000000-0000-0000-0000-000000000000")
                .tenantId("11111111-1111-1111-1111-111111111111")
                .pfxCertificate("certpath.pfx", "password")
                .build();

        // 获取访问令牌
        AccessToken token = credential.getToken(
                new TokenRequestContext().addScopes("https://foo.sharepoint.com/.default")
        ).block();

        if (token == null) {
            System.err.println("获取访问令牌失败");
            return;
        }

        // 构建SharePoint文件请求
        String fileUrl = "https://foo.sharepoint.com/sites/sitename/docpath.docx";
        HttpClient httpClient = new OkHttpAsyncHttpClientBuilder().build();

        try {
            HttpRequest request = new HttpRequest(HttpMethod.GET, new URL(fileUrl))
                    .setHeader("Authorization", "Bearer " + token.getToken())
                    // 下载二进制文件使用application/octet-stream更合适
                    .setHeader("Accept", "application/octet-stream");

            HttpResponse response = httpClient.send(request).block();

            if (response.getStatusCode() == 200) {
                // 读取文件流并保存到本地
                try (InputStream inputStream = response.getBodyAsInputStream().block();
                     FileOutputStream outputStream = new FileOutputStream("downloaded.docx")) {
                    byte[] buffer = new byte[1024];
                    int bytesRead;
                    while ((bytesRead = inputStream.read(buffer)) != -1) {
                        outputStream.write(buffer, 0, bytesRead);
                    }
                    System.out.println("文件下载成功");
                }
            } else {
                System.err.println("请求失败,状态码: " + response.getStatusCode());
                System.err.println("响应内容: " + response.getBodyAsString().block());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

关键调整点

  • 添加main方法作为程序入口,确保代码可执行
  • 增加令牌空值判断,避免空指针异常
  • 修改Accept头为application/octet-stream,适配docx等二进制文件下载
  • 替换字符串读取逻辑为二进制流读写,正确处理非文本文件
  • 补充异常处理,便于排查问题

3. 验证权限配置

确保Azure AD应用配置正确:

  • 已授予SharePoint的Sites.Read.All或对应站点的读取权限
  • 证书已正确上传至Azure AD应用的「证书和机密」模块
  • 租户ID、客户端ID、证书路径及密码均准确无误

内容的提问来源于stack exchange,提问作者K. Oja

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 19:29:56