Sharepoint 2013 MVC 5提供商托管的应用程序。无法使用[SharePointContextFilter]在HttpPost上进行身份验证

时间:2014-05-23 12:03:53

标签: asp.net-mvc-5 sharepoint-2013

过去一周我一直在敲打我无法解决针对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吗?我真的需要有人澄清到底发生了什么......我很感激!

5 个答案:

答案 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)

https://youtu.be/EnT5FtTeWA4?t=28m57s