找到解决方案

解决方案是添加根网站集(因为代码在没有根网站的子网站中运行)。

这个解决方案


重要更新 (根据迄今为止收到的反馈)

我没有在SharePoint2013服务器上安装Visual Studio。所有代码都在Visual Studio2012中使用对所需SharePoint2013Dll的引用进行远程编译,并进行数字签名,以便可以将其部署到SharePoint2013服务器上的全局程序集缓存中。

在最基本的层面上,这句话在 Page_Load();

SPContext.Current.Site.WebApplication.GetIisSettingsWithFallback(
  SPContext.Current.Site.Zone
);

因为 SPContext.Current永远如此 null.

背景资料

客户端需要使用外部用户的基于表单的身份验证和内部用户(企业)的Windows身份验证访问SharePoint站点。已经完成并设置了两个身份验证提供程序,现在获得了默认登录。

Sign In

虽然一切正常,但当客户端希望Windows身份验证自动通过时,Windows身份验证仍会显示提供程序选择屏幕,如果失败,则显示基于表单的身份验证登录屏幕。

在看了各种各样的博客和文章之后,我一直在为此奋斗几天,我觉得我没有进一步的进展,这是令人沮丧的。目前我无法确定我是否错过了一些真正基本的东西。

自定义登录页面

该页面基于以下内容的合并;

  1. %CommonProgramFiles%\Microsoft Shared\Web Server Extensions\15\Template\IdentityModel\Login\default.aspx
  2. %CommonProgramFiles%\Microsoft Shared\Web Server Extensions\15\Template\IdentityModel\Forms\default.aspx

这只是第一次尝试,并意识到我最终不需要所有这些控制,只是想看看事情是如何挂在一起的。

MyCustomSignInModule组装

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using Microsoft.IdentityModel.Web;
using Microsoft.SharePoint;
using Microsoft.SharePoint.IdentityModel;
using Microsoft.SharePoint.IdentityModel.Pages;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Administration.Claims;
using Microsoft.SharePoint.ApplicationRuntime;
using Microsoft.SharePoint.Diagnostics;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;
using System.IdentityModel.Tokens;
using System.Web.Configuration;

namespace MyCustomSignInModule
{
    public class SignInForm : FormsSignInPage
    {
        protected Label DebugText;

        private static SPIisSettings _iisSettings;

        internal static SPIisSettings iisSettings
        {
            get
            {
                if (_iisSettings == null)
                {
                    SPSecurity.RunWithElevatedPrivileges(delegate()
                    {
                        _iisSettings = SPContext.Current.Site.WebApplication.GetIisSettingsWithFallback(SPContext.Current.Site.Zone);
                    });
                }
                return _iisSettings;
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            HttpRequest request = HttpContext.Current.Request;

            bool isWindowsAuth = false;
            string username = request["username"];
            string password = request["password"];


            // If no username is provided, it'll probably be Windows Authentication (NTLMv2 protocol)
            if (String.IsNullOrEmpty(username))
            {
                isWindowsAuth = true;
            }

            try
            {

                //SPIisSettings iisSettings = SPContext.Current.Site.WebApplication.IisSettings[SPUrlZone.Default];

                if (isWindowsAuth)
                {
                    // Windows Authentication it is

                    if (iisSettings.UseWindowsClaimsAuthenticationProvider)
                    {
                        SPAuthenticationProvider provider = iisSettings.WindowsClaimsAuthenticationProvider;
                        RedirectToLoginPage(provider); // This should cause automatic sign in
                    }
                }
                else
                {
                    // FBA authentication it is.

                    SPFormsAuthenticationProvider formsClaimsAuthenticationProvider = iisSettings.FormsClaimsAuthenticationProvider;

                    SecurityToken token = SPSecurityContext.SecurityTokenForFormsAuthentication(new Uri(SPContext.Current.Web.Url), formsClaimsAuthenticationProvider.MembershipProvider, formsClaimsAuthenticationProvider.RoleProvider, username, password, SPFormsAuthenticationOption.PersistentSignInRequest);

                    if (null != token)
                    {
                        EstablishSessionWithToken(token);
                        base.RedirectToSuccessUrl();
                    }
                }
            }
            catch (Exception ex)
            {
                DebugText.Text = ex.ToString();
            }

        }

        // Microsoft.SharePoint.IdentityModel.LogonSelector
        private void RedirectToLoginPage(SPAuthenticationProvider provider)
        {
            string components = HttpContext.Current.Request.Url.GetComponents(UriComponents.Query, UriFormat.SafeUnescaped);
            string url = provider.AuthenticationRedirectionUrl.ToString();
            if (provider is SPWindowsAuthenticationProvider)
            {
                components = EnsureUrlSkipsFormsAuthModuleRedirection(components, true);
            }
            SPUtility.Redirect(url, SPRedirectFlags.Default, this.Context, components);
        }

        // Microsoft.SharePoint.Utilities.SPUtility
        private string EnsureUrlSkipsFormsAuthModuleRedirection
            (string url, bool urlIsQueryStringOnly)
        {
            if (!url.Contains("ReturnUrl="))
            {
                if (urlIsQueryStringOnly)
                {
                    url = url + (string.IsNullOrEmpty(url) ? "" : "&");
                }
                else
                {
                    url = url + ((url.IndexOf('?') == -1) ? "?" : "&");
                }
                url = url + "ReturnUrl=";
            }
            return url;
        }

        // Microsoft.SharePoint.IdentityModel.Pages.IdentityModelSignInPageBase
        private void EstablishSessionWithToken(SecurityToken securityToken)
        {
            if (securityToken == null)
            {
                throw new ArgumentNullException("securityToken");
            }
            SPFederationAuthenticationModule fam = SPFederationAuthenticationModule.Current;
            if (fam == null)
            {
                throw new InvalidOperationException();
            }

            fam.SetPrincipalAndWriteSessionToken(securityToken);
        }

        private SPAuthenticationProvider
                GetAuthenticationProvider(string providerName)
        {
            SPIisSettings iisSettings =
                SPContext.Current.Site.WebApplication.IisSettings[SPUrlZone.Default];

            foreach (SPAuthenticationProvider currentProvider in
                        iisSettings.ClaimsAuthenticationProviders)
            {
                if (currentProvider.DisplayName.ToLower() ==
                            providerName.ToLower())
                {
                    return currentProvider;
                }
            }

            return null;
        }
    }
}

过程

我有一个在VM上运行的测试Sharepoint实例,但没有安装Visual Studio,因为所有开发都是远程完成的。我遵循的当前过程;

  1. 构建C#类库(这将是 MyCustomSignInModule.Dll)
  2. 签署 MyCustomSignInModule.Dll 所以它可以放在VM GAC中。
  3. 登记册 MyCustomSignInModule.Dll 在VM实例上的GAC中。
  4. 储蓄 SignInForm.aspx 进入 %CommonProgramFiles%\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\ 这相当于 <SharePointSiteRoot>/_layouts/ IIS中的虚拟目录。
  5. 在SharePoint管理中心网站中,将"自定义登录"页面设置为"我的页面 ~/_layouts/SignInForm.aspx.
  6. 使用重置IIS iisreset.
  7. 测试访问SharePoint站点(这是它落在哪里)。

问题出在哪里

Sign In Error

如果不是那么清楚,错误是;

System.NullReferenceException: Object reference not set to an instance of an object. at
MyCustomSignInModule.SignInForm.b__0() at 
Microsoft.SharePoint.SPSecurity.<>c__DisplayClass5.b__3() at
Microsoft.SharePoint.Utilities.SecurityContext.RunAsProcess(CodeToRunElevated secureCode) at 
Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(WaitCallback secureCode, Object param) at 
Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(CodeToRunElevated secureCode) at MyCustomSignInModule.SignInForm.get_iisSettings() at 
MyCustomSignInModule.SignInForm.Page_Load(Object sender, EventArgs e) 

SPContext。电流为null为什么?

NullReferenceException 是由 SPContext.Current 是空的,但我无法解释为什么它是空的,到目前为止我看过的任何文章都没有帮助我解决这个问题。我希望通过在这里发布我的整个过程,有人可能会指出我错过了什么或做错了什么。

有帮助吗?

解决方案

终于得到了到底是什么导致了这个问题,首先要感谢两个 @MdMazzotti@休伍德 感谢他们坚持不懈的帮助。

最后,我偶然发现了修复,这部分是因为网站的构建方式。在我的特殊情况下,该网站是作为SharePoint中的子网站构建的,无论出于何种原因,这意味着SharePoint网站的根目录没有网站集,这是导致 Null SPContext 在我的代码中。

添加根网站集后,我的代码开始按预期工作。

其他提示

我只是在这里猜测,但这里有一些我认为可以帮助的事情。

将此JavaScript代码添加到自定义登录页面(在if-语句之前):

SP.SOD.executeFunc('SP.js', 'SP.ClientContext');

您还可以使用控制台将此JavaScript添加到页面中以测试它是否有效:

var clientContext = new  SP.ClientContext.get_current(); 
console.log(clientContext);

如果它返回的东西,那么我们有进步!如果没有,那么我将不得不继续我的搜索,因为我觉得你的问题很有趣。

编辑

而不是使用此服务器端代码:

if (_iisSettings == null)
{
   SPSecurity.RunWithElevatedPrivileges(delegate()
   {
      _iisSettings = SPContext.Current.Site.WebApplication.GetIisSettingsWithFallback(SPContext.Current.Site.Zone);
   });
}
return _iisSettings;

尝试使用此代替:

if (_iisSettings == null)
{
   SPSecurity.RunWithElevatedPrivileges(delegate()
   {
      _iisSettings = Microsoft.SharePoint.SPContext.Current.Site.WebApplication.GetIisSettingsWithFallback(Microsoft.SharePoint.SPContext.Current.Site.Zone);
   });
}
return _iisSettings;

我四处搜索,注意到在我遇到的一些代码示例中,_iisSettings与您的不同。也许这就是为什么你的SPContext。电流为null?

请检查这个答案:https://stackoverflow.com/questions/5081251/how-can-this-throw-a-nullreferenceexception

SPContext。Current在提升的特权下不起作用,所以你必须像上面的答案一样重写。

你能检查这篇MSDN文章吗: http://msdn.microsoft.com/en-us/library/office/ms468609(v=office.14).aspx

我认为因为您在Visual studio中使用C#类库项目,所以您不在web上下文中,无法使用SPContext。当前如上面的MSDN文章中所述。

许可以下: CC-BY-SA归因
scroll top