【问题标题】:MSAL AD token not valid with SharePoint Online CSOMMSAL AD 令牌对 SharePoint Online CSOM 无效
【发布时间】:2020-11-14 19:54:45
【问题描述】:

我能够在桌面 .Net 项目中通过 MSAL 检索和使用访问令牌。我可以成功检索令牌,并且它们在我的 Graph 调用中有效。

但是,尝试将访问令牌与 SharePoint Online CSOM 一起使用会导致 401:未经授权。这类似于accessing sharepoint REST apis using msal throws 401(除了我使用的是 C# 和最新的 CSOM)。

据我了解,MSFT 正试图将开发人员从 ADAL 转移到 MSAL,但令牌似乎存在一些兼容性问题。

是否有人能够指定必要的范围并利用具有 MSAL 持有者授权的 OAuth 令牌来访问 SharePoint Online?

【问题讨论】:

    标签: sharepoint-online msal


    【解决方案1】:

    据我所知,您无法通过 AAD 请求带有客户端/秘密令牌的 SharePoint REST API。但它适用于证书。下面一步一步来:

    由于我遇到了同样的问题,我将在这里发布我是如何通过带有 MSAL 的 AAD 应用程序(OAuth v2 和 AAD v2 端点)连接到 SharePoint API 的。它在 C# 中。

    首先,我只成功了一个证书(据我所知,客户端/秘密方法不起作用)。

    创建证书

    出于测试目的,我创建了一个带有“New-PnPAzureCertificate”的自签名证书,如下所示:

    $secPassword = ConvertTo-SecureString -String "MyPassword" -AsPlainText -Force
    $cert = New-PnPAzureCertificate -OutCert "CertSPUser.cer" -OutPfx "CertSPUser.pfx" -ValidYears 10  -CertificatePassword $secPassword -CommonName "CertSPUser" -Country "FR" -State "France"
    

    -Country-State 参数对测试无关紧要)

    (它也适用于New-SelfSignedCertificate 命令)

    注册证书

    然后,您必须在您的 AAD 应用程序(“.cer”文件)中上传证书:

    配置应用程序 API 权限

    之后,您必须授权 SharePoint API:

    尝试通过 Daemon App (C#) 访问

    NuGet 包(希望我什么都没忘记)

    • Microsoft.SharePointOnline.CSOM
    • Microsoft.Identity.Client

    为了让事情顺利进行,您必须分 3 个步骤来完成(我已经简化了,但您最好通过一些 try/catch 将操作分成方法)

    获取 Pfx 证书

    对于这一步,我强烈建议使用 KeyVault(请参阅帖子底部的链接)

    string certPath = System.IO.Path.GetFullPath(@"C:\PathTo\CertSPUser.pfx");
    X509Certificate2 certificate = new X509Certificate2(certPath, "MyPassword", X509KeyStorageFlags.MachineKeySet);
    

    获取令牌

    string tenantId = "yourTenant.onmicrosoft.com" // Or "TenantId"
    string applicationId = "IdOfYourAADApp"
    IConfidentialClientApplication confApp = ConfidentialClientApplicationBuilder.Create(applicationId)
    .WithAuthority($"https://login.microsoftonline.com/{tenantId}")
    .WithCertificate(certificate)
    .Build();
    
    string sharePointUrl = "https://yourSharePoint.sharepoint.com" // Or "https://yourSharePoint-admin.sharepoint.com" if you want to access the User Profile REST API
    var scopes = new[] { $"{sharePointUrl}/.default" };
    var authenticationResult = await confApp.AcquireTokenForClient(scopes).ExecuteAsync();
    string token = authenticationResult.AccessToken;
    

    测试您的连接

    ClientContext ctx = new ClientContext(sharePointUrl);
    ctx.ExecutingWebRequest += (s, e) =>
    {
          e.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + token;
    };
    
    Web web = ctx.Web;
    ctx.Load(web);
    ctx.Load(web);
    ctx.ExecuteQuery();
    
    // OR if you connect to User Profile ("yourSharePoint-admin.sharepoint.com")
    /* 
    PeopleManager peopleManager = new PeopleManager(ctx);
    var personProperties = peopleManager.GetUserProfileProperties("i:0#.f|membership|employee.mail@tenant.onmicrosoft.com");
    ctx.ExecuteQuery();
    */
    

    如果我没有遗漏任何内容,您应该获得一些网络/用户信息! ?

    希望对你有帮助。

    编辑(2020 年 11 月 14 日):即使在我的 API 权限屏幕截图中,我添加了应用程序权限“User.ReadWrite.All”,如果您尝试更新用户配置文件,它不会工作。要解决此问题,您必须将 AAD 应用程序注册为旧版 SharePoint 仅应用程序主体(客户端 ID/机密)。更多信息here.

    感谢 @laurakokkarinen@mmsharepoint 的文章真正帮助了我(herehere

    【讨论】:

    • 这是一篇出色的文章!一个问题:您是否知道为什么使用 ClientId/ClientSecret 组合不再适用于 CSOM?使用证书比较麻烦。
    • 好问题!我不记得它在过去已经起作用了。如果您想使用客户端 ID/密钥对,我知道的唯一方法是使用传统的 SharePoint 仅应用程序方法。小心使用这个:通过“AppRegNew.aspx”生成的秘密只有一年的有效期。如果你想配置过期延迟,可以关注@sergei-sergeev 写的很棒的文章:spblog.net/post/2018/08/24/…
    • 我遇到了您提到的用户配置文件版本的问题。所以我正在尝试使用仅限应用程序的身份验证来执行我的编辑操作。但是,这样做的 nuget 包 SharePointPnPCoreOnline 是针对 .net 4.7 框架的。我正在使用最新版本的 Microsoft.SharePointOnline.CSOM 处理 .net core 3.1 项目。您是否对针对 .net core 3.1 的 SharePointPnPCoreOnline 包的等效项提出建议,以允许我使用仅应用身份验证生成 clientContext?谢谢
    • 没关系,我在这里找到了合适的解决方案:linkedin.com/pulse/…github.com/elnurrr/CSOM-NET-Standard
    • @Jows 仅供参考,PnP 团队正在准备下一个框架,该框架将接替 PnP-Sites-Core(又名 SharePointPnPCoreOnline),它将与 .Net Core 兼容:PnP Framework。您找到的代码与 PnP 框架中使用的代码完全相同(实际上是预览版),您可以找到 here
    【解决方案2】:

    不确定您为什么直接使用 MSAL 来访问 SharePoint Online API。 最简单的方法应该是使用Microsoft.SharePointOnline.CSOM

    var clientContext = new ClientContext(siteUrl);
    clientContext.Credentials = new SharePointOnlineCredentials(userName, securedPassword);
    

    您已经完成了 CSOM API。

    但我认为 MSAL 也应该可以。 请记住,您获得的令牌是为某些资源授予的。将您的令牌复制到http://jwt.ms/ 并查看aud

    如果此字段包含https://graph.microsoft.com,则它对您无效https://yourtenant.sharepoint.com,您需要不同的!

    您应该能够使用Microsoft.Identity.Client 请求正确的令牌

    var authority = $"https://login.microsoftonline.com/{tenantId}";
    var app = ConfidentialClientApplicationBuilder.Create(clientId)
        .WithClientSecret(clientSecret)
        .WithAuthority(new Uri(authority))
        .Build();
    
    var scopes = new[] { "https://yourtenant.sharepoint.com/.default" };
    var authenticationResult = await app.AcquireTokenForClient(scopes)
        .ExecuteAsync();
    

    因此,authenticationResult.AccessToken 应包含对 SharePoint Online REST API 有效的访问令牌。 (https://yourtenant.sharepoint.com/.default 表示您请求为您的 Azure AD 应用程序配置的所有范围)

    当你解码新的 jet 令牌时,它应该是这样的

    【讨论】:

    • 请参阅@michaelmaillot 答案:您在使用客户端密码时会获得一个 jwt 令牌,但当您尝试使用它时,SharePoint REST API 会返回“401 未授权”。使用证书代替工作正常。不确定这是否记录在某处,但当然真的很烦人。
    • @krombi CSOM 和 SharePointOnlineCredentials 仅适用于 Windows 上的 .NET Framework。如果您的目标是 Linux 上的 .NET Core,那么您必须遵循 Microsoft 的最新指南并使用 MSAL。他们最新的文档详细介绍了此信息。
    • 这里描述了类似的方法 - stackoverflow.com/a/63386756/987850
    猜你喜欢
    • 2023-03-19
    • 2019-10-24
    • 2020-10-17
    • 2021-01-02
    • 1970-01-01
    • 2021-11-28
    • 1970-01-01
    • 2015-03-28
    • 1970-01-01
    相关资源
    最近更新 更多