Die benutzerdefinierte Anmeldeseite hat einen SPContext.Strom, der immer null ist
-
10-12-2019 - |
Frage
Die Lösung gefunden
Die Lösung bestand darin, eine Stammwebsitesammlung hinzuzufügen (da der Code auf einer Unterwebsite ohne Stammwebsite ausgeführt wurde).
Sehen Diese Lösung
Wichtiges Update (basierend auf bisher eingegangenem Feedback)
Ich habe Visual Studio nicht auf dem SharePoint 2013-Server installiert.Der gesamte Code wird in Visual Studio 2012 remote mithilfe von Verweisen auf die erforderlichen SharePoint 2013-DLLs kompiliert und digital signiert, damit er im globalen Assemblycache auf dem SharePoint 2013-Server bereitgestellt werden kann.
Auf der grundlegendsten Ebene versagt diese Aussage an der Stelle von
Page_Load()
;SPContext.Current.Site.WebApplication.GetIisSettingsWithFallback( SPContext.Current.Site.Zone );
Da
SPContext.Current
is immernull
.
Hintergrund
Der Client benötigt eine SharePoint-Site, auf die über die formularbasierte Authentifizierung für externe Benutzer und die Windows-Authentifizierung für interne Benutzer (Unternehmen) zugegriffen werden kann.Habe beide Authentifizierungsanbieter durchlaufen und eingerichtet und erhalte jetzt die Standardanmeldung.
Obwohl alles funktioniert, zeigt die Windows-Authentifizierung weiterhin den Anbieterauswahlbildschirm an, wenn der Client möchte, dass die Windows-Authentifizierung nur automatisch durchlaufen wird, und zeigt einen Anmeldebildschirm für die formularbasierte Authentifizierung an, wenn dies fehlschlägt.
Nachdem ich mir tagelang verschiedene Blogs und Artikel angesehen habe, habe ich das Gefühl, dass ich nicht weiter bin und das ist deprimierend.Im Moment kann ich nicht trainieren, ob mir etwas wirklich Grundlegendes fehlt.
Benutzerdefinierte Anmeldeseite
Die Seite basiert auf einem Zusammenschluss von;
%CommonProgramFiles%\Microsoft Shared\Web Server Extensions\15\Template\IdentityModel\Login\default.aspx
%CommonProgramFiles%\Microsoft Shared\Web Server Extensions\15\Template\IdentityModel\Forms\default.aspx
Dies ist nur ein erster Versuch und mir ist klar, dass ich irgendwann nicht mehr all diese Steuerelemente brauche, sondern nur sehen wollte, wie die Dinge zusammenhängen.
<%@ Assembly Name="Microsoft.SharePoint.IdentityModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="SharepointIdentity" Namespace="Microsoft.SharePoint.IdentityModel" Assembly="Microsoft.SharePoint.IdentityModel, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Assembly Name="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>
<%@ Page Language="C#" Inherits="MyCustomSignInModule.SignInForm, MyCustomSignInModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f2ae721af94bf9e9" MasterPageFile="~/_layouts/15/errorv15.master"%>
<%@ Import Namespace="Microsoft.SharePoint.WebControls" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=15.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<asp:Content ContentPlaceHolderId="PlaceHolderPageTitleInTitleArea" runat="server">
<SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" Id="ClaimsLogonPageTitleInTitleArea" />
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderPageTitle" runat="server">
<SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" Id="ClaimsFormsPageTitle" />
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
<SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" Id="ClaimsLogonPageMessage" />
<br />
<br />
<SharepointIdentity:LogonSelector ID="ClaimsLogonSelector" runat="server" />
<div id="SslWarning" style="color:red;display:none">
<SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" Id="ClaimsFormsPageMessage" />
</div>
<script language="javascript" >
if (document.location.protocol != 'https:') {
var SslWarning = document.getElementById('SslWarning');
SslWarning.style.display = '';
}
</script>
<asp:login id="signInControl" FailureText="<%$Resources:wss,login_pageFailureText%>" runat="server" width="100%">
<layouttemplate>
<asp:label id="FailureText" class="ms-error" runat="server"/>
<table width="100%">
<tr>
<td nowrap="nowrap"><SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,login_pageUserName%>" EncodeMethod='HtmlEncode'/></td>
<td width="100%"><asp:textbox id="UserName" autocomplete="off" runat="server" class="ms-inputuserfield" width="99%" /></td>
</tr>
<tr>
<td nowrap="nowrap"><SharePoint:EncodedLiteral runat="server" text="<%$Resources:wss,login_pagePassword%>" EncodeMethod='HtmlEncode'/></td>
<td width="100%"><asp:textbox id="password" TextMode="Password" autocomplete="off" runat="server" class="ms-inputuserfield" width="99%"/></td>
</tr>
<tr>
<td colspan="2" align="right"><asp:button id="login" commandname="Login" text="<%$Resources:wss,login_pagetitle%>" runat="server" /></td>
</tr>
<tr>
<td colspan="2"><asp:checkbox id="RememberMe" text="<%$SPHtmlEncodedResources:wss,login_pageRememberMe%>" runat="server" /></td>
</tr>
</table>
</layouttemplate>
</asp:login>
<asp:label id="DebugText" class="ms-error" runat="server"/>
</asp:Content>
MyCustomSignInModule Zusammenbau
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;
}
}
}
Prozess
Ich habe eine Test-Sharepoint-Instanz auf der VM ausgeführt, aber kein Visual Studio installiert, da die gesamte Entwicklung remote erfolgt.Dem aktuellen Prozess folge ich;
- Erstellen Sie eine C # -Klassenbibliothek (dies wird sein
MyCustomSignInModule.Dll
) - Unterzeichnen
MyCustomSignInModule.Dll
so kann es in der VM GAC platziert werden. - Registrieren
MyCustomSignInModule.Dll
im GAC auf der VM-Instanz. - Speichern
SignInForm.aspx
in die%CommonProgramFiles%\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\
welches ist das Äquivalent von<SharePointSiteRoot>/_layouts/
virtuelles Verzeichnis in IIS. - Legen Sie auf der SharePoint-Website für die Zentraladministration die benutzerdefinierte Anmeldeseite auf meine Seite fest
~/_layouts/SignInForm.aspx
. - Setzen Sie IIS mit zurück
iisreset
. - Testen Sie den Zugriff auf die SharePoint-Site (hier fällt sie um).
Problem
Wenn es nicht so klar ist, ist der Fehler;
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)
In: SPContext.Strom ist null warum?
Der NullReferenceException
wird verursacht durch SPContext.Current
null sein, aber ich kann nicht trainieren, warum es null ist und keine Anzahl von Artikeln, die ich mir angesehen habe, hat mir bisher geholfen, dies zu lösen.Ich hoffe, dass mich jemand durch das Posten meines gesamten Prozesses hier auf das hinweisen kann, was ich vermisse oder falsch mache.
Lösung
Endlich auf den Grund gekommen, was das Problem verursacht hat, möchte ich zunächst beiden danken @MdMazzotti und @Hugh Wood für ihre beharrliche Hilfe.
Am Ende bin ich über die Lösung gestolpert, die sich teilweise als die Art und Weise herausstellte, wie die Site aufgebaut war.In meinem speziellen Fall wurde die Site als Unterwebsite in SharePoint erstellt. Aus irgendeinem Grund bedeutete dies, dass sich im Stammverzeichnis der SharePoint-Website keine Websitesammlung befand, was die Ursache für die Null
SPContext
in meinem Code.
Nach dem Hinzufügen einer Stamm-Websitesammlung funktionierte mein Code wie erwartet.
Andere Tipps
Ich rate hier nur, aber hier sind einige Dinge, von denen ich denke, dass sie helfen könnten.
Fügen Sie diesen JavaScript-Code der benutzerdefinierten Anmeldeseite hinzu (vor Ihrer if-Anweisung):
SP.SOD.executeFunc('SP.js', 'SP.ClientContext');
Sie können dieses JavaScript auch zu Ihrer Seite hinzufügen, um über die Konsole zu testen, ob es funktioniert oder nicht:
var clientContext = new SP.ClientContext.get_current();
console.log(clientContext);
Wenn es etwas zurückgibt, dann haben wir Fortschritte!Wenn nicht, dann muss ich meine Suche fortsetzen, da ich Ihre Frage interessant finde.
BEARBEITEN
Anstatt diesen serverseitigen Code zu verwenden:
if (_iisSettings == null)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
_iisSettings = SPContext.Current.Site.WebApplication.GetIisSettingsWithFallback(SPContext.Current.Site.Zone);
});
}
return _iisSettings;
Versuchen Sie stattdessen, dies zu verwenden:
if (_iisSettings == null)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
_iisSettings = Microsoft.SharePoint.SPContext.Current.Site.WebApplication.GetIisSettingsWithFallback(Microsoft.SharePoint.SPContext.Current.Site.Zone);
});
}
return _iisSettings;
Ich habe mich umgesehen und festgestellt, dass sich in einigen der Codebeispiele, auf die ich gestoßen bin, die _iisSettings von Ihren unterschieden.Vielleicht ist das der Grund für Ihren SPContext .Strom ist null?
Bitte überprüfen Sie diese Antwort:https://stackoverflow.com/questions/5081251/how-can-this-throw-a-nullreferenceexception
In: SPContext.Current funktioniert nicht unter erhöhten Berechtigungen, daher müssen Sie wie in der obigen Antwort umschreiben.
Können Sie diesen MSDN-Artikel überprüfen: http://msdn.microsoft.com/en-us/library/office/ms468609 (v = Büro.14).aspx
Ich denke, weil Sie ein C # -Klassenbibliotheksprojekt in Visual Studio verwenden, befinden Sie sich nicht in einem Webkontext und können SPContext nicht verwenden.Aktuell wie im obigen MSDN-Artikel erläutert.