(401) 从 SharePoint 下载文件时发生未经授权的异常
(401) Unauthorized exception while downloading file from SharePoint
我已经使用 OAuth 机制为 SharePoint Online 服务器生成了一个访问令牌。我使用此令牌通过 CSOM 创建 ClientContext。虽然我能够无缝访问所有站点、库和文件夹,但我收到错误
The remote server returned an error: (401) Unauthorized.
正在从 SharePoint Online 下载文件。下面是我用于文件下载的代码:
var clientContext = TokenHelper.GetClientContextWithAccessToken("https://adventurer.sharepoint.com/Subsite1", accessToken);
var list = clientContext.Web.Lists.GetByTitle("SubSite 1 Library 1");
string vquery = @"<View Scope='RecursiveAll'><Query><Where><Eq><FieldRef Name='UniqueId' /><Value Type='Lookup'>" + "6718053d-a785-489c-877f-5a4b88dcb2a7" + "</Value></Eq></Where></Query></View>";
CamlQuery query = new CamlQuery();
query.ViewXml = vquery;
var listItems = list.GetItems(query);
clientContext.Load(listItems, items => items.Take(1).Include(item => item.File));
clientContext.ExecuteQuery();
var fileRef = listItems[0].File.ServerRelativeUrl;
var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, fileRef);
我不明白此错误的根本原因,因为我正在传递具有正确访问令牌的客户端上下文。我想知道 OpenBinaryDirect 是否有使用访问令牌的限制?如果不是,上面的代码有什么问题?是否有任何其他替代方法可用于使用访问令牌下载?
我正在使用 C#,这是我目前从 SharePoint Online 检索文档的方式。我在 gridview 中向用户展示了他们的文档列表,因此我用这些文档填充了一个 DataTable。我不确定使用访问令牌的方法,但如果您能够像我一样使用服务帐户,那么希望这对您有所帮助。
命名空间
using Microsoft.SharePoint.Client;
using SP = Microsoft.SharePoint.Client;
对象属性
SecureString securePassword = new SecureString();
private string username = "";
ClientContext context = new SP.ClientContext("https://<root>.sharepoint.com/<site collection (unless root)>/<site>");
构造函数(我就是这样验证的)
public SharePoint()
{
securePassword = convertToSecureString(System.Web.Configuration.WebConfigurationManager.AppSettings["O365PW"]);
username = System.Web.Configuration.WebConfigurationManager.AppSettings["O365UN"];
context.Credentials = new SharePointOnlineCredentials(username, securePassword);
}
获取文档的方法
public DataTable GetDocuments(int changeID)
{
DataTable dt = new DataTable("ChangeDocuments");
DataRow dr = dt.NewRow();
dt.Columns.Add("Title");
dt.Columns.Add("URL");
dt.Columns.Add("ChangeID");
dt.Columns.Add("Modified");
dt.Columns.Add("ID");
// The SharePoint web at the URL.
Web web = context.Web;
// We want to retrieve the web's properties.
context.Load(web);
// We must call ExecuteQuery before enumerate list.Fields.
context.ExecuteQuery();
// Assume the web has a list named "Announcements".
SP.List oList = context.Web.Lists.GetByTitle("Name of your document library");
// This creates a CamlQuery that has a RowLimit of 100, and also specifies Scope="RecursiveAll"
// so that it grabs all list items, regardless of the folder they are in.
CamlQuery query = CamlQuery.CreateAllItemsQuery(100);
query.ViewXml = "<View><Query><Where><Eq><FieldRef Name='ChangeID'/>" +
"<Value Type='Number'>" + changeID + "</Value></Eq></Where></Query><RowLimit>100</RowLimit></View>";
SP.ListItemCollection items = oList.GetItems(query);
// Retrieve all items in the ListItemCollection from List.GetItems(Query).
context.Load(items);
context.ExecuteQuery();
foreach (Microsoft.SharePoint.Client.ListItem listItem in items)
{
// We have all the list item data. For example, Title.
dr = dt.NewRow();
dr["Title"] = listItem["FileLeafRef"];
if (String.IsNullOrEmpty(listItem["ServerRedirectedEmbedUrl"].ToString()))
{
dr["URL"] = "<root>/<site>/<document library>" + listItem["FileLeafRef"].ToString();
}
else
{
dr["URL"] = listItem["ServerRedirectedEmbedUrl"];
}
dr["ChangeID"] = listItem["ChangeID"];
dr["Modified"] = Convert.ToDateTime(listItem["Modified"]).ToString("MMM.dd,yyyy h:mm tt");
dr["ID"] = listItem["ID"];
dt.Rows.Add(dr);
}
return dt;
}
将密码转换为安全字符串的方法
private SecureString convertToSecureString(string strPassword)
{
var secureStr = new SecureString();
if (strPassword.Length > 0)
{
foreach (var c in strPassword.ToCharArray()) secureStr.AppendChar(c);
}
return secureStr;
}
在尝试了很多替代方案之后,我得出结论,OpenBinaryDirect() 不能与 OAuth 令牌一起使用。我能够使用其他两种方法从 SharePoint Online 下载文件。我在这里发布答案,以便它可以帮助某人:
方法 1 (OpenBinaryStream):
var file = clientContext.Web.GetFileByServerRelativeUrl(fileRef);
clientContext.Load(file);
clientContext.ExecuteQuery();
ClientResult<Stream> streamResult = file.OpenBinaryStream();
clientContext.ExecuteQuery();
虽然此方法非常有效,但 OpenBinaryStream
在 Microsoft.SharePoint.Client.dll
<= v 14.0.0.0 中不可用。
方法 2(WebClient 或其他 Http 请求):
string downloadUrl = HostURL + "/_api/web/getfilebyserverrelativeurl('" + fileRef + "')/$value";
WebClient client = new WebClient();
client.Headers.Add("Authorization", "Bearer " + accessToken);
client.DownloadFile(downloadUrl, filePath);
请注意我用于 WebClient 的下载 URL。普通文件 URL 无法从 SharePoint Online 下载文件。
我已经使用 OAuth 机制为 SharePoint Online 服务器生成了一个访问令牌。我使用此令牌通过 CSOM 创建 ClientContext。虽然我能够无缝访问所有站点、库和文件夹,但我收到错误
The remote server returned an error: (401) Unauthorized.
正在从 SharePoint Online 下载文件。下面是我用于文件下载的代码:
var clientContext = TokenHelper.GetClientContextWithAccessToken("https://adventurer.sharepoint.com/Subsite1", accessToken);
var list = clientContext.Web.Lists.GetByTitle("SubSite 1 Library 1");
string vquery = @"<View Scope='RecursiveAll'><Query><Where><Eq><FieldRef Name='UniqueId' /><Value Type='Lookup'>" + "6718053d-a785-489c-877f-5a4b88dcb2a7" + "</Value></Eq></Where></Query></View>";
CamlQuery query = new CamlQuery();
query.ViewXml = vquery;
var listItems = list.GetItems(query);
clientContext.Load(listItems, items => items.Take(1).Include(item => item.File));
clientContext.ExecuteQuery();
var fileRef = listItems[0].File.ServerRelativeUrl;
var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, fileRef);
我不明白此错误的根本原因,因为我正在传递具有正确访问令牌的客户端上下文。我想知道 OpenBinaryDirect 是否有使用访问令牌的限制?如果不是,上面的代码有什么问题?是否有任何其他替代方法可用于使用访问令牌下载?
我正在使用 C#,这是我目前从 SharePoint Online 检索文档的方式。我在 gridview 中向用户展示了他们的文档列表,因此我用这些文档填充了一个 DataTable。我不确定使用访问令牌的方法,但如果您能够像我一样使用服务帐户,那么希望这对您有所帮助。
命名空间
using Microsoft.SharePoint.Client;
using SP = Microsoft.SharePoint.Client;
对象属性
SecureString securePassword = new SecureString();
private string username = "";
ClientContext context = new SP.ClientContext("https://<root>.sharepoint.com/<site collection (unless root)>/<site>");
构造函数(我就是这样验证的)
public SharePoint()
{
securePassword = convertToSecureString(System.Web.Configuration.WebConfigurationManager.AppSettings["O365PW"]);
username = System.Web.Configuration.WebConfigurationManager.AppSettings["O365UN"];
context.Credentials = new SharePointOnlineCredentials(username, securePassword);
}
获取文档的方法
public DataTable GetDocuments(int changeID)
{
DataTable dt = new DataTable("ChangeDocuments");
DataRow dr = dt.NewRow();
dt.Columns.Add("Title");
dt.Columns.Add("URL");
dt.Columns.Add("ChangeID");
dt.Columns.Add("Modified");
dt.Columns.Add("ID");
// The SharePoint web at the URL.
Web web = context.Web;
// We want to retrieve the web's properties.
context.Load(web);
// We must call ExecuteQuery before enumerate list.Fields.
context.ExecuteQuery();
// Assume the web has a list named "Announcements".
SP.List oList = context.Web.Lists.GetByTitle("Name of your document library");
// This creates a CamlQuery that has a RowLimit of 100, and also specifies Scope="RecursiveAll"
// so that it grabs all list items, regardless of the folder they are in.
CamlQuery query = CamlQuery.CreateAllItemsQuery(100);
query.ViewXml = "<View><Query><Where><Eq><FieldRef Name='ChangeID'/>" +
"<Value Type='Number'>" + changeID + "</Value></Eq></Where></Query><RowLimit>100</RowLimit></View>";
SP.ListItemCollection items = oList.GetItems(query);
// Retrieve all items in the ListItemCollection from List.GetItems(Query).
context.Load(items);
context.ExecuteQuery();
foreach (Microsoft.SharePoint.Client.ListItem listItem in items)
{
// We have all the list item data. For example, Title.
dr = dt.NewRow();
dr["Title"] = listItem["FileLeafRef"];
if (String.IsNullOrEmpty(listItem["ServerRedirectedEmbedUrl"].ToString()))
{
dr["URL"] = "<root>/<site>/<document library>" + listItem["FileLeafRef"].ToString();
}
else
{
dr["URL"] = listItem["ServerRedirectedEmbedUrl"];
}
dr["ChangeID"] = listItem["ChangeID"];
dr["Modified"] = Convert.ToDateTime(listItem["Modified"]).ToString("MMM.dd,yyyy h:mm tt");
dr["ID"] = listItem["ID"];
dt.Rows.Add(dr);
}
return dt;
}
将密码转换为安全字符串的方法
private SecureString convertToSecureString(string strPassword)
{
var secureStr = new SecureString();
if (strPassword.Length > 0)
{
foreach (var c in strPassword.ToCharArray()) secureStr.AppendChar(c);
}
return secureStr;
}
在尝试了很多替代方案之后,我得出结论,OpenBinaryDirect() 不能与 OAuth 令牌一起使用。我能够使用其他两种方法从 SharePoint Online 下载文件。我在这里发布答案,以便它可以帮助某人:
方法 1 (OpenBinaryStream):
var file = clientContext.Web.GetFileByServerRelativeUrl(fileRef);
clientContext.Load(file);
clientContext.ExecuteQuery();
ClientResult<Stream> streamResult = file.OpenBinaryStream();
clientContext.ExecuteQuery();
虽然此方法非常有效,但 OpenBinaryStream
在 Microsoft.SharePoint.Client.dll
<= v 14.0.0.0 中不可用。
方法 2(WebClient 或其他 Http 请求):
string downloadUrl = HostURL + "/_api/web/getfilebyserverrelativeurl('" + fileRef + "')/$value";
WebClient client = new WebClient();
client.Headers.Add("Authorization", "Bearer " + accessToken);
client.DownloadFile(downloadUrl, filePath);
请注意我用于 WebClient 的下载 URL。普通文件 URL 无法从 SharePoint Online 下载文件。