Schreiben einer benutzerdefinierten Formularanmeldeseite für SharePoint 2010 – Teil 2
Schreiben einer benutzerdefinierten Formularanmeldeseite für SharePoint 2010 – Teil 2
NEUE EINLEITUNG ZU DIESEM BEITRAG, EIN OFFENER KOMMENTAR FÜR DIE WEBSITEBESITZER:
Nachdem die Blogwebsite zur neuesten Version dieses was auch immer aktualisiert wurde, ist die Formatierung eine Katastrophe! Ich verwende in der Regel viel Zeit damit, dem miserablen Markup (oder dessen Fehlen) gerecht zu werden. BITTE WENDEN SIE SICH AN DEN WEBMASTER, UND TEILEN SIE IHM MIT, WIR SCHWIERIG DIESE GRAUENVOLL FORMATIERTE SEITE ZU LESEN IST! In der Zwischenzeit werde ich versuchen, ein Word-Dokument mit dem ursprünglichen Beitrag anzuhängen, wenn immer dies möglich ist. Da sage noch einer, Technologie sei ein Segen! OK, fangen wir an...
In Teil 1 dieser Serie, den Sie unter https://blogs.msdn.com/b/sharepoint_de/archive/2010/11/17/schreiben-einer-benutzerdefinierten-formularanmeldeseite-f-252-r-sharepoint-160-2010-teil-160-1.aspx finden, habe ich die Erstellung einer vollkommen neuen Formularanmeldeseite erläutert. Das Szenario dafür war der Bedarf nach einer Erweiterung der Möglichkeiten, die die vorgefertigte Benutzeroberfläche zur Verfügung stellt, beispielsweise eine Authentifizierung mit zwei Faktoren. In diesem Beitrag werde ich ein anderes Szenario erläutern. In diesem Szenario ist die vorgefertigte Benutzeroberfläche in Ordnung, es soll jedoch zur Anmeldezeit etwas hinzugefügt werden.
In diesem Szenario sollen alle Benutzer den Nutzungsbedingungen der Website zustimmen, bevor sie darauf zugreifen. Daher erstelle ich zunächst eine neue Anmeldeseite. Ich füge einen Handler für das Anmeldeereignis hinzu, und dabei wird überprüft, ob die Benutzer ein Cookie besitzen, das mitteilt, dass sie den Nutzungsbedingungen bereits zugestimmt haben. Wenn dies nicht der Fall ist, werden die Benutzer auf eine Seite umgeleitet, auf der sie ein Kontrollkästchen aktivieren können, mit dem sie ihr Einverständnis erklären, anschließend werden sie zurück zur Anmeldeseite geleitet. Wenn sich die Benutzer erneut anmelden, lässt sich feststellen, dass das Cookie für die Anerkennung der Nutzungsbedingungen vorhanden ist, und sie können direkt zu der gewünschten Ressource, einer Startseite, einem Dokument usw., weitergeleitet werden.
Für den Anfang erstelle ich meine neue Anmeldeseite. Gerade habe ich meinem Projekt eine neue ASPX-Seite hinzugefügt. In diesem Projekt muss ich Verweise zu Microsoft.SharePoint und Microsoft.SharePoint.IdentityModel hinzufügen. Details zum Hinzufügen von Verweisen zu Microsoft.SharePoint.IdentityModel finden Sie in Teil 1, zu dem ich oben den Link angegeben habe. In dem meiner Seite zugrundeliegenden Code verwende ich wieder mehrere using-Anweisungen. Die folgenden Anweisungen wurden verwendet:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.IdentityModel.Pages;
using System.Diagnostics;
Da die Seite, die ich schreibe, eine Anmeldeseite für die formularbasierte Authentifizierung ist, muss von FormsSignInPage geerbt werden. Meine Klassendeklaration sieht folgendermaßen aus:
public partial class AgreeLogin : FormsSignInPage
Die erste Aufgabe, die ich im Code ausführe, ist das Überschreiben des Ladeereignisses der Seite. Ich füge einen Handler für das Anmeldeereignis für das ASP.NET-Anmeldesteuerelemente der Seite hinzu. Das Überschreiben sieht für das Laden der Seite folgendermaßen aus:
protected override void OnLoad(EventArgs e)
{
try
{
base.OnLoad(e);
this.signInControl.LoggingIn +=
new LoginCancelEventHandler(signInControl_LoggingIn);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
Hinweis: Ich habe dies in einen try…catch-Block gesetzt, wenn Sie nämlich beim Seiten-Markup einen Fehler machen, wie ich weiter unten erläutere, wird ein Fehler ausgeben, wenn base.OnLoad(e) aufgerufen wird. Im Anschluss erläutere ich die Implementierung des LoggingIn-Ereignishandlers:
void signInControl_LoggingIn(object sender, LoginCancelEventArgs e)
{
//look for a cookie; if not there then redirect to our accept terms page
const string AGREE_COOKIE = "SignedTermsAgreement";
try
{
//we want to check for our cookie here
HttpCookieCollection cookies = HttpContext.Current.Request.Cookies;
HttpCookie ck = cookies[AGREE_COOKIE];
if (ck == null)
//user doesn't have the cookie indicating that they've signed the
//terms of use so redirect them
Response.Redirect("AgreeTerms.aspx?" +
Request.QueryString.ToString());
}
catch (Exception ex)
{
Debug.WriteLine("There was an error processing the request: " +
ex.Message);
}
}
Wenn ich mit der Anmeldung beginne, suche ich zunächst nach dem Cookie, das mitteilt, dass der Benutzer den Nutzungsbestimmungen der Website zugestimmt hat. Wenn das Cookie nicht gefunden wird, wird der Benutzer zurück zur Seite AgreeTerms.aspx geleitet. Ich füge die vollständige Abfragezeichenfolge hinzu, die die Anmeldeseite empfangen hat, da diese mitteilt, welche Ressource der Benutzer angefordert hat, als er die Anmeldeseite aufgerufen hat. Ich weiß somit, wohin der Benutzer weitergeleitet werden muss, nachdem er den Nutzungsbestimmungen zugestimmt hat. Dabei muss beachtet werden, dass ich eine Änderung an der Datei web.config für meine SharePoint-Webanwendung vornehmen muss, damit auf die Seite für die Nutzungsbedingungen anonym zugegriffen werden kann. Wenn es sich dabei um eine gesicherte Ressource wie jede andere Seite handelte, würde eine Endlosschleife entstehen. Wenn das Cookie nicht vorhanden ist, wird der Benutzer zur Seite AgreeTerms.aspx geleitet, da diese jedoch gesichert ist, würde der Benutzer zurück zur benutztendefinierten Anmeldeseite geleitet und immer so weiter. Daher ändere ich die Datei web.config dahingehend, dass ich den folgenden Eintrag direkt hinter dem schließenden Tag </system.web> einfüge:
<location path="_layouts/AgreeTerms.aspx">
<system.web>
<authorization>
<allow users="*" />
</authorization>
</system.web>
</location>
Jetzt kann auf die Seite AgreeTerms.aspx ohne Authentifizierung zugegriffen werden. Ich möchte Sie nicht mit der Benutzeroberfläche der Seite langweilen, aber diese ist in Ihrem zugrundeliegenden Code sehr einfach:
protected void SubmitBtn_Click(object sender, EventArgs e)
{
const string AGREE_COOKIE = "SignedTermsAgreement";
try
{
//make sure the checkbox is checked
if ((AgreeChk.Checked) && (Request.Browser.Cookies))
{
//create the cookie
HttpCookie ck = new HttpCookie(AGREE_COOKIE, "true");
//set the expiration so it's persisted
ck.Expires = DateTime.Now.AddYears(3);
//write it out
HttpContext.Current.Response.Cookies.Add(ck);
//get the src attribute from the query string and redirect there
Response.Redirect(Request.QueryString["Source"]);
}
else
StatusLbl.Text = "You must agree to the terms of use before continuing.";
}
catch (Exception ex)
{
string msg = "There was an error processing the request: " + ex.Message;
Debug.WriteLine(msg);
StatusLbl.Text = msg;
}
}
Dies sollte weitgehend klar sein. Wenn das Kontrollkästchen aktiviert wird, wird das Cookie vergeben, und der Benutzer wird per Response.Redirect zu der ursprünglich angeforderten Quelle weitergeleitet. Auf diese Weise wird der Benutzer zurück zur Anmeldeseite geleitet, und bei dieser Anmeldung wird das Cookie festgestellt, und die Anmeldung kann ausgeführt werden. Wenn der Benutzer den Nutzungsbestimmungen nicht zustimmt, erfolgt keinerlei Weiterleitung.
Das wäre alles in Bezug auf den Code, es gibt jedoch noch eine EXTREM wichtige Sache zu erledigen, das ist das Markup der Anmeldeseite. Wie ich bereits weiter oben erläutert habe, gibt es große Probleme, wenn beim Markup Fehler auftreten. Das Folgende ist das Markup, mit dem Sie beginnen sollten:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AgreeLogin.aspx.cs" Inherits="FormsLoginPage.AgreeLogin,FormsLoginPage, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cf32e76ff986e00f" MasterPageFile="~/_layouts/simple.master" %>
<%@ Assembly Name="Microsoft.SharePoint.ApplicationPages, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>
<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %> <%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %> <%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<asp:Content ContentPlaceHolderId="PlaceHolderPageTitle" runat="server">
<SharePoint:EncodedLiteral ID="ClaimsFormsPageTitle" runat="server" text="<%$Resources:wss,login_pagetitle%>" EncodeMethod='HtmlEncode'/>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderPageTitleInTitleArea" runat="server">
<SharePoint:EncodedLiteral ID="ClaimsFormsPageTitleInTitleArea" runat="server" text="<%$Resources:wss,login_pagetitle%>" EncodeMethod='HtmlEncode'/>
</asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderSiteName" runat="server"/>
<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
<SharePoint:EncodedLiteral runat="server" EncodeMethod="HtmlEncode" ID="ClaimsFormsPageMessage" />
<asp:login id="signInControl" FailureText="<%$Resources:wss,login_pageFailureText%>" runat="server" width="100%">
<layouttemplate>
<asp:label id="FailureText" class="ms-error" runat="server"/>
<table class="ms-input">
<colgroup>
<col width="25%"/>
<col width="75%"/>
</colgroup>
<tr>
<td nowrap="nowrap"><SharePoint:EncodedLiteral ID="EncodedLiteral3" runat="server" text="<%$Resources:wss,login_pageUserName%>" EncodeMethod='HtmlEncode'/></td>
<td><asp:textbox id="UserName" autocomplete="off" runat="server" class="ms-long ms-login-textbox"/></td>
</tr>
<tr>
<td nowrap="nowrap"><SharePoint:EncodedLiteral ID="EncodedLiteral4" runat="server" text="<%$Resources:wss,login_pagePassword%>" EncodeMethod='HtmlEncode'/></td>
<td><asp:textbox id="password" TextMode="Password" autocomplete="off" runat="server" class="ms-long ms-login-textbox"/></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:Content>
Die einzige Änderung, die Sie vornehmen, ist die erste Zeile, die @Page-Richtlinie.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="AgreeLogin.aspx.cs" Inherits="FormsLoginPage.AgreeLogin,FormsLoginPage, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cf32e76ff986e00f" MasterPageFile="~/_layouts/simple.master" %>
Die gelb markierten Teile sollten zu dem starken Namen Ihrer benutzerdefinierten Assembly geändert werden.
Nachdem Sie dies alles zusammengefügt und kompiliert haben, müssen Sie Ihre Assembly nur noch im GAC registrieren und die ASPX-Seite(n) in das Layoutverzeichnis kopieren. Der letzte Schritt, bevor Sie das Ergebnis ausprobieren können, ist die Änderung der Anmeldeseite für die Webanwendungszone, in der Sie FBA verwenden. Wechseln Sie in der Zentraladministration zu Anwendungsverwaltung, Webanwendungen verwalten. Wählen Sie Ihre Webanwendung aus, und klicken Sie in der Symbolleiste auf die Schaltfläche Authentifizierungsanbieter. Klicken Sie auf den Link zu der Zone, die Sie ändern möchten, und klicken Sie in dem folgenden Dialogfeld auf das Optionsfeld Benutzerdefinierte Anmeldeseite, und geben Sie die URL zu Ihrer Anmeldeseite ein. In meinem Fall war dies _layouts/AgreeLogin.aspx. Speichern Sie Ihre Änderungen, und Sie können sich bei Ihrer Website anmelden.
Abschließend sehen Sie hier, wie es aussieht, wenn ich mich bei meiner Website über meine benutzerdefinierten Seiten anmelde. Ich hoffe, dieser Beitrag hilft Ihnen dabei, das Gleiche zu erreichen!
1. Erste Anmeldung
2. Seite für die Nutzungsbedingungen
3. Abschließender Zugriff auf die Website
Es handelt sich hierbei um einen übersetzten Blogbeitrag. Sie finden den Originalartikel unter Writing A Custom Forms Login Page for SharePoint 2010 Part 2