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

如何通过Apache POI访问需认证的SharePoint存储的.xlsx文件?

嘿,这个问题我太熟了!SharePoint的受保护文件确实没法直接用URL.openStream()访问——因为它需要身份认证,你之前的代码没带任何凭据,自然会返回403。给你几个简便可行的方案,你可以根据自己的场景挑:

方案1:用Microsoft Graph API(官方推荐,长期维护)

这是最稳妥的方式,因为Microsoft Graph是官方提供的统一接口,专门用来访问Office 365资源,不用自己折腾复杂的认证逻辑。

步骤:

  1. 先在Azure Portal注册一个AD应用,拿到租户ID、客户端ID、客户端密钥,并给这个应用分配SharePoint站点的访问权限(比如Sites.Read.All)。
  2. 引入Microsoft Graph的Java SDK依赖,然后写代码获取文件流:
<!-- Maven依赖 -->
<dependency>
    <groupId>com.microsoft.graph</groupId>
    <artifactId>microsoft-graph</artifactId>
    <version>6.3.0</version>
</dependency>
<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-identity</artifactId>
    <version>1.12.0</version>
</dependency>
import com.microsoft.graph.models.*;
import com.microsoft.graph.requests.*;
import com.azure.identity.ClientSecretCredential;
import com.azure.identity.ClientSecretCredentialBuilder;
import java.io.InputStream;
import java.util.concurrent.CompletableFuture;

public class SharePointFileFetcher {
    public static void main(String[] args) {
        // 替换成你的实际参数
        String tenantId = "your-tenant-id";
        String clientId = "your-client-id";
        String clientSecret = "your-client-secret";
        String siteId = "your-sharepoint-site-id";
        String driveId = "your-document-library-id";
        String fileId = "your-file-id";

        // 创建认证凭据
        ClientSecretCredential credential = new ClientSecretCredentialBuilder()
                .tenantId(tenantId)
                .clientId(clientId)
                .clientSecret(clientSecret)
                .build();

        // 构建Graph客户端
        GraphServiceClient<Request> graphClient = GraphServiceClient.builder()
                .authenticationProvider(request -> {
                    String token = credential.getToken("https://graph.microsoft.com/.default").block().getToken();
                    request.addHeader("Authorization", "Bearer " + token);
                    return CompletableFuture.completedFuture(null);
                })
                .buildClient();

        // 获取文件输入流
        try (InputStream fileStream = graphClient.sites(siteId).drives(driveId).items(fileId)
                .content()
                .buildRequest()
                .get()) {
            // 直接把这个流传给Apache POI处理
            // Workbook workbook = WorkbookFactory.create(fileStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

优势:

  • 官方维护,兼容性好,后续SharePoint更新也不用自己改代码
  • 支持各种权限场景,能灵活控制应用的访问范围
方案2:用Apache HttpClient处理NTLM认证(适合内部域环境)

如果你的SharePoint是内部部署的,用Windows域账号就能登录,那这个方案最直接——用Apache HttpClient的NTLM认证模块,直接传入域账号密码就行。

import org.apache.http.HttpEntity;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import java.io.InputStream;

public class SharePointNTLMAuth {
    public static void main(String[] args) {
        // 替换成你的域账号和文件URL
        String domainUsername = "your-domain\\your-username";
        String password = "your-password";
        String fileUrl = "https://example.sharepoint.com/something/something1/file.xlsx";

        CredentialsProvider credsProvider = new BasicCredentialsProvider();
        credsProvider.setCredentials(AuthScope.ANY,
                new NTCredentials(domainUsername, password, "", ""));

        try (CloseableHttpClient httpClient = HttpClients.custom()
                .setDefaultCredentialsProvider(credsProvider)
                .build()) {
            HttpGet httpGet = new HttpGet(fileUrl);
            try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    try (InputStream fileStream = entity.getContent()) {
                        // 交给Apache POI处理
                        // Workbook workbook = WorkbookFactory.create(fileStream);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

优势:

  • 代码简单,不需要额外注册应用
  • 适合内部企业域环境的SharePoint
方案3:直接调用SharePoint REST API(轻量无依赖)

如果不想引入太多SDK,也可以直接调用SharePoint的REST API,手动获取OAuth令牌后请求文件流。

import java.io.InputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;

public class SharePointRESTFetcher {
    public static void main(String[] args) {
        // 替换成你的实际参数
        String tenantId = "your-tenant-id";
        String clientId = "your-client-id";
        String clientSecret = "your-client-secret";
        String siteUrl = "https://example.sharepoint.com";
        String fileRelativePath = "/something/something1/file.xlsx";

        HttpClient httpClient = HttpClient.newHttpClient();

        try {
            // 第一步:获取OAuth访问令牌
            HttpRequest tokenRequest = HttpRequest.newBuilder()
                    .uri(URI.create("https://login.microsoftonline.com/" + tenantId + "/oauth2/v2.0/token"))
                    .header("Content-Type", "application/x-www-form-urlencoded")
                    .POST(HttpRequest.BodyPublishers.ofString(String.format(
                            "grant_type=client_credentials&scope=%s/.default&client_id=%s&client_secret=%s",
                            siteUrl, clientId, clientSecret), StandardCharsets.UTF_8))
                    .build();

            HttpResponse<String> tokenResponse = httpClient.send(tokenRequest, HttpResponse.BodyHandlers.ofString());
            // 快速解析令牌(生产环境建议用JSON库比如Jackson)
            String accessToken = tokenResponse.body().split("\"access_token\":\"")[1].split("\"")[0];

            // 第二步:请求文件流
            HttpRequest fileRequest = HttpRequest.newBuilder()
                    .uri(URI.create(siteUrl + "/_api/web/getfilebyserverrelativeurl('" + fileRelativePath + "')/$value"))
                    .header("Authorization", "Bearer " + accessToken)
                    .GET()
                    .build();

            HttpResponse<InputStream> fileResponse = httpClient.send(fileRequest, HttpResponse.BodyHandlers.ofInputStream());
            try (InputStream fileStream = fileResponse.body()) {
                // 传给Apache POI处理
                // Workbook workbook = WorkbookFactory.create(fileStream);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

优势:

  • 轻量,只依赖Java原生的Http客户端,不需要额外SDK
  • 灵活,能自定义请求细节

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:31:12