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

如何从C#控制台应用程序对启用SSO的SharePoint进行身份认证?

在启用SSO的SharePoint中通过C# .NET创建文件夹并上传文件

SharePoint启用SSO(通常基于Azure AD)时,无需硬编码用户名密码,可通过MSAL.NET + Microsoft Graph API实现认证、文件夹创建和文件上传,以下是分场景的实操方案:

一、核心认证方案

1. 桌面/交互式应用

适合有UI的客户端应用,通过弹出SSO登录窗口完成认证:
首先安装NuGet包:Microsoft.Identity.Client、Microsoft.Graph

using Microsoft.Identity.Client;
using Microsoft.Graph;

var clientId = "你的Azure AD应用客户端ID";
var tenantId = "你的租户ID";
var scopes = new[] { "https://graph.microsoft.com/Sites.ReadWrite.All" };

// 初始化公共客户端应用
var publicClientApp = PublicClientApplicationBuilder
    .Create(clientId)
    .WithTenantId(tenantId)
    .WithRedirectUri("http://localhost")
    .Build();

// 获取SSO令牌(自动唤起企业登录界面)
var authResult = await publicClientApp.AcquireTokenInteractive(scopes).ExecuteAsync();

// 构造Graph客户端
var graphClient = new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMsg) =>
{
    requestMsg.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authResult.AccessToken);
}));

2. 服务端/后台应用(无人值守)

适合无UI的后台服务,使用Azure AD应用密钥完成认证:
同样安装上述NuGet包,代码如下:

using Microsoft.Identity.Client;
using Microsoft.Graph;

var clientId = "你的Azure AD应用客户端ID";
var tenantId = "你的租户ID";
var clientSecret = "你的Azure AD应用密钥";
var scopes = new[] { "https://graph.microsoft.com/.default" };

// 初始化机密客户端应用
var confidentialClientApp = ConfidentialClientApplicationBuilder
    .Create(clientId)
    .WithTenantId(tenantId)
    .WithClientSecret(clientSecret)
    .Build();

// 获取应用级令牌
var authResult = await confidentialClientApp.AcquireTokenForClient(scopes).ExecuteAsync();

// 构造Graph客户端
var graphClient = new GraphServiceClient(new DelegateAuthenticationProvider(async (requestMsg) =>
{
    requestMsg.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", authResult.AccessToken);
}));

二、创建多级文件夹

通过Graph API递归创建文件夹,支持路径自动拆分:

var siteId = "你的SharePoint站点ID";
var driveId = "文档库的Drive ID";
var targetFolderPath = "/项目文档/2024Q3/技术资料"; // 目标文件夹路径

var folderSegments = targetFolderPath.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
DriveItem parentFolder = null;

foreach (var folderName in folderSegments)
{
    // 检查文件夹是否已存在
    var existingFolders = await graphClient.Sites[siteId].Drives[driveId].Root.Children
        .Request()
        .Filter($"name eq '{folderName}' and folder ne null")
        .GetAsync();

    if (existingFolders.Count == 0)
    {
        // 创建新文件夹,冲突时自动重命名
        var newFolder = new DriveItem
        {
            Name = folderName,
            Folder = new Folder(),
            AdditionalData = new Dictionary<string, object>
            {
                {"@microsoft.graph.conflictBehavior", "rename"}
            }
        };
        parentFolder = await graphClient.Sites[siteId].Drives[driveId].Root.Children.Request().AddAsync(newFolder);
    }
    else
    {
        parentFolder = existingFolders.First();
    }
}

三、上传文件(PDF/Excel/Word等)

支持任意文件类型,直接流式上传:

var localFilePath = @"C:\本地文件\项目方案.pdf"; // 本地文件路径
var fileName = Path.GetFileName(localFilePath);

using (var fileStream = new FileStream(localFilePath, FileMode.Open, FileAccess.Read))
{
    var uploadedItem = await graphClient.Sites[siteId].Drives[driveId].Items[parentFolder.Id]
        .ItemWithPath(fileName)
        .Content
        .Request()
        .PutAsync<DriveItem>(fileStream);
}

四、关键注意事项

  • 权限配置:在Azure AD门户中,给应用分配对应的Graph权限:交互式应用用Sites.ReadWrite.All(委派权限),后台应用用Sites.ReadWrite.All(应用权限),并完成管理员同意。
  • 站点/Drive ID获取:如果不知道站点ID,可通过站点域名查询:await graphClient.Sites.GetByPath("/sites/你的站点域名", "你的租户域名").Request().GetAsync();Drive ID可通过站点的文档库查询:await graphClient.Sites[siteId].Drives.Request().GetAsync()。
  • SharePoint本地版(ADFS SSO):若为本地SharePoint,可使用SharePointPnPCoreOnline库,通过AuthenticationManager.GetADFSContext(siteUrl, adfsMetadataUrl)获取认证上下文,再调用PnP API操作文件夹和文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 16:47:45