Écriture d’une page de connexion personnalisée dans le cadre d’une authentification par formulaire pour SharePoint 2010 (Partie 2)

Écriture d’une page de connexion personnalisée dans le cadre d’une authentification par formulaire pour SharePoint 2010 (Partie 2)

NOUVELLE PRÉFACE POUR CETTE PUBLICATION ET COMMENTAIRE OUVERT À L’ATTENTION DU PROPRIÉTAIRE DU SITE :

Depuis que le site de blog a fait l’objet d’une énième mise à niveau, la mise en forme ne ressemble plus à grand-chose. Je passe généralement beaucoup de temps à essayer de corriger dans l’urgence le marquage pathétique (ou défaut de marquage) engendré par cette nouvelle version. N’HÉSITEZ PAS À CONTACTER L’ADMINISTRATEUR WEB POUR LUI FAIRE PART DE LA DIFFICULTÉ DE LIRE CES BILLETS AFFREUSEMENT MIS EN FORME ! Entre-temps, j’essaierai ,chaque fois que possible, de joindre un document Word comportant le billet initialement tapé par mes soins. Qui a dit que la technologie n’est que pureté ? Bon, c’est parti...

Dans la partie 1 de cette série, disponible à l’adresse http://blogs.msdn.com/b/sharepoint_fr/archive/2010/11/16/201-criture-d-une-page-de-connexion-personnalis-233-e-dans-le-cadre-d-une-authentification-par-formulaire-pour-sharepoint-160-2010-partie-160-1.aspx, j’ai expliqué comment créer une page de connexion avec authentification par formulaire. Le scénario qui sous-tend cette création est la nécessité de recourir à des informations qui ne sont pas disponibles par le biais de l’interface utilisateur prédéfinie, comme dans le cas d’une authentification à deux facteurs. Dans ce billet, je vais décrire un scénario différent. En l’occurrence, l’interface utilisateur prédéfinie convient, mais nous souhaitons effectuer une « opération » supplémentaire au moment de la connexion.

Dans le cadre de ce scénario, je souhaite que tous les utilisateurs acceptent les conditions d’utilisation du site avant d’accéder à celui-ci pour la première fois. Par conséquent, je vais commencer par créer une page de connexion. Je vais ajouter un gestionnaire pour l’événement de connexion et, dans cet événement, je vais déterminer s’il existe un cookie indiquant que l’utilisateur a accepté les conditions d’utilisation. Si l’utilisateur n’a pas accepté les conditions, il est redirigé vers une page qui lui permet d’activer une case à cocher indiquant qu’il accepte les conditions ; une fois la case à cocher activée, il est redirigé vers la page de connexion. Lorsque l’utilisateur se reconnecte, le code écrit par mes soins détermine s’il possède le cookie des conditions d’utilisation ; si tel est le cas, l’utilisateur est simplement redirigé vers la ressource qu’il demandée (la page d’accueil, un document, etc.).

Pour commencer, je vais créer ma page de connexion. J’ai simplement ajouté une nouvelle page ASPX à mon projet. Dans ce projet, je vais devoir ajouter des références à Microsoft.SharePoint et à Microsoft.SharePoint.IdentityModel. Pour plus d’informations sur la façon d’ajouter la référence à Microsoft.SharePoint.IdentityModel, reportez-vous à la partie 1, dont vous trouverez le lien plus haut. Dans le code sous-jacent de ma page, je vais réutiliser une série d’instructions using. Voici celles que j’ai utilisées :

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;

Étant donné que la page que je suis en train d’écrire est une page de connexion pour l’authentification par formulaire, elle doit hériter de FormsSignInPage. Ma déclaration de classe se présente comme suit :

public partial class AgreeLogin : FormsSignInPage

La première chose que je vais effectuer dans le code consiste à substituer l’événement de chargement de page. Dans cet événement, je vais ajouter un gestionnaire pour l’événement de connexion pour le contrôle de connexion ASP.NET de la page. Voilà ce à quoi ressemble la substitution pour le chargement de la page :

protected override void OnLoad(EventArgs e)

{

try

       {

             base.OnLoad(e);

             this.signInControl.LoggingIn +=

                   new LoginCancelEventHandler(signInControl_LoggingIn);

}

catch (Exception ex)

       {

       Debug.WriteLine(ex.Message);

       }

}

Une remarque à ce stade : j’ai utilisé un bloc try…catch, car si le marquage de la page est défectueux, ce que je vais expliquer plus loin, vous obtenez une erreur lorsque base.OnLoad(e) est appelé. À présent, je vais vous montrer l’implémentation du gestionnaire d’événements LoggingIn :

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);

       }

}

À ce stade, au démarrage de la procédure de connexion, le système recherche le cookie qui indique que l’utilisateur a accepté les conditions d’utilisation du site. Si le cookie est introuvable, l’utilisateur est redirigé vers ma page AgreeTerms.aspx. J’inclus la chaîne de requête complète que la page de connexion a reçue, car elle indique la ressource que l’utilisateur était en train de demander lorsqu’il a atteint la page de connexion ; cela permet de savoir vers où rediriger l’utilisateur une fois qu’il aura accepté les conditions d’utilisation. À ce stade, veuillez noter que je dois apporter une modification à mon fichier web.config pour mon application Web SharePoint afin que la page des conditions d’utilisation soit accessible de façon anonyme. Sinon, s’il s’agissait d’une ressource sécurisée à l’image d’une page sur deux dans le site, l’utilisateur serait pris dans une boucle sans fin. Le système pourrait considérer que, l’utilisateur ne possédant pas le cookie, il suffirait de le rediriger vers la page AgreeTerms.aspx, mais dans la mesure où il s’agit d’une ressource sécurisée, l’utilisateur serait indéfiniment redirigé vers la page de connexion personnalisée. Par conséquent, j’ai modifié le fichier web.config de manière à inclure l’entrée suivante juste avant la balise </system.web> fermante :

<location path="_layouts/AgreeTerms.aspx">

<system.web>

<authorization>

<allow users="*" />

</authorization>

</system.web>

</location>

À présent, il est possible d’attendre la page AgreeTerms.aspx sans être authentifié. Je ne vais pas vous ennuyer avec l’interface utilisateur de la page maintenant, mais sachez qu’elle est assez simple dans le code sous-jacent de cette page :

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;

}

}

Cela doit être assez clair : si l’utilisateur active la case à cocher, il obtient le cookie et Response.Redirect le redirige vers la source initialement demandée. Cette opération redirige l’utilisateur vers la page de connexion et cette fois, lorsqu’il se connecte, il obtient le cookie et tout fonctionne facilement. Si l’utilisateur n’accepte pas les conditions d’utilisation, il n’est redirigé nulle part.

Du point de vue du codage, l’exposé est terminé, mais il y a autre chose que vous devez absolument maîtriser, à savoir le marquage de la page de connexion. Comme je l’ai expliqué précédemment, si le marquage est incorrect, vous connaîtrez de nombreux problèmes. Par conséquent, pour commencer, voici le marquage sur lequel vous devez vous appuyer :

<%@ 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>

La seule chose à réellement modifier est la toute première ligne, à savoir la directive @Page.

<%@ 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" %>

La partie surlignée en jaune doit être remplacée par le nom fort de votre assembly personnalisé.

Une fois toutes ces informations agencées et compilées, il vous suffit d’inscrire votre assembly dans le GAC et de copier vos pages ASPX dans le répertoire des dispositions. La dernière étape avant un premier véritable test consiste à modifier la page de connexion associée à la zone d’application Web dans laquelle vous utilisez l’authentification par formulaire. Accédez à l’Administration centrale, puis cliquez sur Gestion des applications et sur Gérer les applications Web. Sélectionnez votre application Web, puis cliquez sur le bouton Fournisseurs d’authentification dans la barre d’outils. Cliquez sur le lien de la zone à modifier, puis, dans la boîte de dialogue qui apparaît, cliquez sur la case d’option Page de connexion personnalisée et entrez l’URL de votre page de connexion. Dans mon cas, il s’agissait de _layouts/AgreeLogin.aspx. Enregistrez vos modifications ; vous êtes alors prêt à vous connecter à votre site.

Enfin, voici ce à quoi cela ressemblait lorsque je me suis connecté à mon site avec mes pages personnalisées ; j’espère que ce billet vous aidera à accomplir la même procédure !

1. Connexion initiale

2. Page des conditions d’utilisation

3. Enfin, connexion au site

 

Ce billet de blog a été traduit de l’anglais. L’article d’origine est disponible à la page Writing A Custom Forms Login Page for SharePoint 2010 Part 2.