c# - 如何使用应用程序级身份验证/访问 token 访问 Sharepoint 文件?

标签 c# azure api sharepoint

我尝试在无需用户登录的情况下访问 Sharepoint 文件。

我可以通过以下任一方式获取访问 token 方法一:

var client = new RestClient("https://login.microsoftonline.com/app's-tenant-id-here/oauth2/token");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Cookie", "fpc=AjMRWuGtzbFJgrxV0V1kMCkUHKO3AQAAAEqqRtgOAAAA");
request.AddParameter("resource", "https://graph.microsoft.com");
request.AddParameter("grant_type", "client_credentials");
request.AddParameter("client_id", "client-id-here");
request.AddParameter("client_secret", ".client-secret-here");
IRestResponse response = client.Execute(request);

或方法 2 - (此错误给出以下错误:“AppForSharePointOnlineWebToolkit.TokenHelper”的类型初始值设定项引发异常。)

string siteUrl = "https://the-site-I-am-trying-to-access.sharepoint.com/sites/xxx/";
string realm = TokenHelper.GetRealmFromTargetUrl(new Uri(siteUrl));
string accessToken2 = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, new Uri(siteUrl).Authority, realm).AccessToken;
using (ClientContext cc = TokenHelper.GetClientContextWithAccessToken(siteUrl, accessToken2))
{
       cc.Load(cc.Web, p => p.Title);
       cc.ExecuteQuery();
       Console.WriteLine(cc.Web.Title);
}

甚至方法3

HttpWebRequest endpointRequest = (HttpWebRequest)WebRequest.Create("https://the-site-I-am-trying-to-access.sharepoint.com/sites/xxx/_api/web/getfilebyserverrelativeurl('~/Shared%20Documents/picture.png')");
endpointRequest.Method = "GET";
endpointRequest.Accept = "application/json;odata=verbose";
endpointRequest.Headers.Add("Authorization", "Bearer " + accessToken);
HttpWebResponse endpointResponse = (HttpWebResponse)endpointRequest.GetResponse();

都没有成功访问 Sharepoint。

所以我的问题是,我做错了什么还是有其他方法可以实现这一目标?

最佳答案

首先,如果可能的话,我建议使用 Graph API。至少它是查询数据的首选方式,并且使事情变得更加容易。

要通过 Graph API 访问 Microsoft 365 世界中的数据,需要在 azure portal 中创建新的应用注册。 > Azure Active Directory > 应用程序注册。

请参阅此链接了解更多信息:MS Docs App Registration

创建新应用后,配置访问 SharePoint 数据所需的范围和权限(例如 Sites.ReadWrite.All 以获得完全访问权限)。

之后,只需使用生成和提供的 clientID、clientSecret、tenantID 和范围来请求新的访问 token 。

我创建了一个类来为我执行所有 http 请求:

public class GraphClient
{
  private const string LOGIN_URL = "https://login.microsoftonline.com/{0}/oauth2/v2.0/token";
  private const string BASE_URL  = "https://graph.microsoft.com";

  protected internal string HttpBaseAddress { get; }

  protected internal readonly HttpClient HttpClient;

  public GraphClient(string tenantId, string clientId, string clientSecret, string version = "1.0")
  {
    var msgHandler = new GraphAuthMessageHandler(string.Format(LOGIN_URL, tenantId),
                                                         $"{BASE_URL}/.default",
                                                         clientId,
                                                         clientSecret,
                                                         new HttpClientHandler());
    HttpBaseAddress = $"{BASE_URL}/v{version}/";
    HttpClient = new HttpClient(msgHandler)
    {
      BaseAddress = new Uri(HttpBaseAddress),
      Timeout     = new TimeSpan(0, 2, 0)
    };

    HttpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
    HttpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
    HttpClient.DefaultRequestHeaders.Add("Prefer", "odata.include-annotations=\"*\"");
    HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
  }
}

提供的 MessageHangler 请求 token 并将提供的访问 token 添加到 header :

using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Threading;
using System.Threading.Tasks;

public class GraphAuthMessageHandler : DelegatingHandler
{
  private readonly string _loginUrl;
  private readonly string _clientId;
  private readonly string _clientSecret;
  private readonly string _scope;

  public GraphAuthMessageHandler(string loginUrl, string scope, string clientId, string clientSecret, HttpMessageHandler innerHandler)
            : base(innerHandler)
  {
    _loginUrl     = loginUrl;
    _clientId     = clientId;
    _clientSecret = clientSecret;
    _scope        = scope;
  }

  protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
  {
    var result = await AcquireAccessToken();
    request.Headers.Authorization = new AuthenticationHeaderValue(result.TokenType, result.AccessToken);

    return await base.SendAsync(request, cancellationToken);
  }

  private async Task<AuthResponse> AcquireAccessToken()
  {
    var httpClient = new HttpClient();
    var values = new List<KeyValuePair<string, string>>
    {
      new("client_id", _clientId),
      new("client_secret", _clientSecret),
      new("scope", _scope),
      new("grant_type", "client_credentials")
    };

    var response = await httpClient.PostAsync(_loginUrl, new FormUrlEncodedContent(values));
    return await response.Content.ReadFromJsonAsync<AuthResponse>();
  }
}

编辑这是 AuthResponse 类,它只是将 json 响应映射到 C# 对象:

using System.Text.Json.Serialization;

public class AuthResponse
{
  [JsonPropertyName("token_type")]   public string TokenType   { get; set; }
  [JsonPropertyName("expires_in")]   public int    ExpiresIn   { get; set; }
  [JsonPropertyName("access_token")] public string AccessToken { get; set; }
}

然后简单地使用它:

var driveId = "your-drive-id-here";
var itemId = "your-item-id-here";
var client = new GraphClient(TENANT_ID, CLIENT_ID, CLIENT_SECRET);

var response = await client.HttpClient.GetAsync($"drives/{driveId}/items/{itemId}/content");

if (response.IsSuccessStatusCode)
{
  var fileStream = await response.Content.ReadAsStreamAsync();
  // do something with stream
}

// handle errors here

Microsoft Docs是让它工作的良好开端,它对我使用 Graph API 以及 Graph Explorer 帮助很大。测试对端点的查询和请求。

附注这只是一个简单的示例,当然还有改进的空间,但这有望为您指明正确的方向;)

关于c# - 如何使用应用程序级身份验证/访问 token 访问 Sharepoint 文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67775586/

相关文章:

c# - 将常规属性转换为自动实现的属性

azure - 更新 Azure 表存储记录时如何避免竞争条件

sql - 联邦sql View azure

ruby-on-rails - 如何使Ruby方法结束/停止另一个请求? (rails API)

c# - 关于 C# 中自定义集合的问题

c# - 根据 ListView 中的位置触发按钮可见性

Azure 免费网站重定向到 www 且未找到页面

api - 如何从银行账户下载信息?

java - 当我在手机上运行此代码时强制关闭

c# - C# Facebook Sdk 是否有可用的 Monotouch 端口?