过去一周我一直在敲打我无法解决针对sharepoint提供商托管应用的正确身份验证的一些问题。
我目前正在为公司的Sharepoint在线开发一个sharepoint应用程序。我正在使用Visual Studio 2013.我将该应用程序部署为公司的Windows Azure门户上的云服务。一切顺利到我需要制作HttpPost的时候,然后应用程序无法进行身份验证。 Conroller的设计如下:
[SharePointContextFilter]
public ActionResult Index()
{
UserSingleton user_temp = UserSingleton.GetInstance();
User spUser = null;
SharePointContext spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext);
using (var clientContext = spContext.CreateUserClientContextForSPHost())
{
if (clientContext != null)
{
spUser = clientContext.Web.CurrentUser;
clientContext.Load(spUser, user => user.Title, user => user.Email);
clientContext.ExecuteQuery();
....code....
}
}
....code....
return View();
}
加载索引页面很顺利,操作会创建用户上下文,这一切都很好。当我尝试提交HttpPost时会出现问题:
[HttpPost]
[ValidateAntiForgeryToken]
[SharePointContextFilter]
public ActionResult GetService(System.Web.Mvc.FormCollection fc)
{
PlannedHours ph = this.PopulateModel(fc);
if (ph == null)
return View("NoInfoFound");
ViewData["PlannedHours"] = ph;
return View("Index");
}
当我通过帖子按钮拨打此电话时,我收到“无法确定您的身份。请通过启动您网站上安装的应用再试一次。” Shared / Error.cshtml视图。问题是当我删除[SharePointContextFilter]然后它工作,但这意味着请求不通过[SharePointContextFilter]因此它没有正确认证?或者是吗?因为它无法验证用户的合法性。
当我不删除[SharePointContextFilter]并调用帖子时,我注意到了一件事,那么网址最终没有{StandardTokens}查询。是假设是这样的 - 我的意思是它像hostname.com/Home/GetService一样,但是当我使用actionlink时,spcontext.js总是将{StandardTokens}查询附加到基本URL - 像hostname.com/Home一样/ ActionNAme /?SPHostUrl = HTTPS%3A%2F%2FSHAREPOINTPAGEURL ....
我注意到我调用hostname.com/Home/ActionNAme/而没有附加无法通过[SharePointContextFilter]的查询。
我是sharepoint 2013和MVC 5(Razor)的新手,所以如果你知道为什么我的HttpPost无法通过[SharePointContextFilter]尝试解释我或给出任何建议。我尝试过使用HttpGet但是,当我调用具有[SharePointContextFilter]的HttpGet并附加SPHostUrl =令牌时,它可以工作。但后来我无法使用[ValidateAntiForgeryToken]。甚至在这样的应用程序中是否需要[ValidateAntiForgeryToken],因为[SharePointContextFilter]总是检查用户的合法性?我现在很困惑。网上有大量的资料可供阅读,没有什么可以解释何时附加这些标准代币,什么时候使用[SharePointContextFilter]等。事实上我第一次在我的网站上开发一个sharepoint应用程序。生活和我一直在研究和编码过去3周。所以我的知识还很有限,在回答时要记住这一点。在此先感谢,我希望我能对所发生的事情做一些澄清!
----------------------------- UPDATE ----------------- -----------------------
好的,快速更新。我发现了一些相当奇怪的东西。 SharePointContextFilterAttribute.cs
public class SharePointContextFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
Uri redirectUrl;
switch (SharePointContextProvider.CheckRedirectionStatus(filterContext.HttpContext, out redirectUrl))
{
case RedirectionStatus.Ok:
return;
case RedirectionStatus.ShouldRedirect:
filterContext.Result = new RedirectResult(redirectUrl.AbsoluteUri);
break;
case RedirectionStatus.CanNotRedirect:
filterContext.Result = new ViewResult { ViewName = "Error" };
break;
}
}
}
始终返回最后一个案例(RedirectionStatus.CanNotRedirect),因为方法SharePointContextProvider.CheckRedirectionStatus(filterContext.HttpContext,out redirectUrl)包含一些我无法解决的问题。
首先:
Uri spHostUrl = SharePointContext.GetSPHostUrl(httpContext.Request);
if (spHostUrl == null)
{
return RedirectionStatus.CanNotRedirect;
}
好的,我理解 - 如果httpContext.Request不包含spHostUrl,它将无法重定向。由于某种原因必须在那里。
但是以下内容:
if (StringComparer.OrdinalIgnoreCase.Equals(httpContext.Request.HttpMethod, "POST"))
{
return RedirectionStatus.CanNotRedirect;
}
等WHAAAT?!?不允许POST?!!?这里发生了什么?我真的不知道我做错了什么或什么?我甚至可以使用SharePointContext.cs吗?我真的需要有人澄清到底发生了什么......我很感激!
答案 0 :(得分:8)
以上解决方案对我不起作用。
对我来说有同样的问题return RedirectToAction("Index");
导致错误。
我把它改为:
return RedirectToAction("Index", new {SPHostUrl = SharePointContext.GetSPHostUrl(HttpContext.Request).AbsoluteUri});
并且有效。
我不确定这是你的问题的解决方案,因为你正在做返回视图,但它可能会帮助某人:)
答案 1 :(得分:1)
我有同样的问题,花了几天时间来解决这个问题。我不知道为什么SharePointContextFilter无法正常工作且没有重定向。所以我的应用程序是通过POST方法启动的,我在刷新页面时重新提交了表单确认对话框。我还“无法确定您的身份。请通过启动您网站上安装的应用再试一次。”
要修复我使用Post/Redirect/Get模式的问题。我将我的Index操作更改为将RedirectToAction转换为另一个IndexGet操作。但是你应该有两个IndexGet方法 - 用于post和get。
最后我得到了三个动作。索引操作重定向到POST IndexGet操作:
public ActionResult Index()
{
return RedirectToAction("IndexGet");
}
Post和Get的两个IndexGet方法具有相同的代码:
[HttpPost]
public ActionResult IndexGet(string tmp)
{
//your code from Index action
return View();
}
[HttpGet]
public ActionResult IndexGet()
{
//your code from Index action
return View();
}
所以它以这种方式工作:在开始时,通过POST调用Index操作。它重定向到POST IndexGet操作,在这个位置SharePointContextFilter正常工作,并通过GET调用IndexGet。这种模式解决了我的问题。
答案 2 :(得分:1)
我同意Libin / user24176!
当从一个控制器的操作导航到另一个控制器时,SharePoint会引用SPHostUrl来获取上下文。但是,当我发现问题是由于缺少SPHostUrl时,我尝试在RedirectToAction方法中附加SPHostUrl&一切都开始有效了。
解决方案: 将SPHostUrl附加到RedirectToAction方法调用 使用Controller的RedirectToAction方法将用户重定向到另一个Action并且它是重载是一种常见的情况。
默认情况下,您可以使用以下代码行轻松地将用户重定向到“另一个”操作
return RedirectToAction("Another");
假设您正在从HomeController执行此调用,您的浏览器将被重定向到www.PHapp.com/Home/Another并再次丢失SPHostUrl
要解决此问题,您可以轻松地将SPHostUrl传递给RedirectToAction方法,或者您可以覆盖BaseController类中的方法(每个MVC应用程序都应该具有该方法)并将实际重定向更改为此类
return RedirectToAction("Another",new
{ SPHostUrl = SharePointContext.GetSPHostUrl(HttpContext.Request).AbsoluteUri });
这会强制您的浏览器使用以下网址请求操作www.PHapp.com/Home/Fallback?SPHostUrl = ...“
当然,使用MVC构建SharePoint应用程序时还存在其他缺陷,但是根据客户的要求,能够根据每个控制器方法创建SharePoint上下文是一种关键。
- #Update 2 --- 最初我在IE&该网站在IE较低版本中加载没有SPHostURL的控制器Action,后来我更新了_Layouts HTML- header部分,强制IE在最新版本中打开:
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
此后,MVC PH App会在所有Action链接中绑定SPHotsURL。
答案 3 :(得分:0)
我有同样的错误。如果发布请求不包含有错误的表单数据,则此情况下的发布请求是正常的。例如,此类Post请求可能包含此类错误:
SPErrorInfo:端点地址&#39;&#39;与应用的终端不匹配&#39;
。如果您在POST中看到此类错误,则您的SharePointContextFilterAttribute类肯定会在您的问题中描述的POST中引发错误。但是,如果POST请求是&#34;好&#34;请求在抛出错误之前处理它并返回重定向确定。
因此,此处的任务是不更改SharePointContextFilterAttribute的行为,而是解决问题。例如,上面的错误表明我为ClientID指定了错误的域名。您可以在Microsoft Seller Dashboard中生成ClientID,它需要指定域。如果它与托管提供商托管应用程序的域不同,则会抛出错误。
https是一样的...如果重定向网址不是HTTPS,它也会抛出错误。出于某些原因,当您从Visual Studio启动应用程序时,它不会抛出此类错误,但如果您将应用程序部署到App Catalog,则会抛出此类错误。
所以,我建议你打开Fiddler并研究你的POST要求。很可能你会看到错误,这清楚地解释了问题。
答案 4 :(得分:-2)
您可能在重定向操作中丢失了Sharepoint上下文。
从29分钟开始观看SP大会的演示。您正在描述的错误是有意产生的,并且提供了一个解决方案(在新的RedirectAction中提供了Sharepoint Context)