Recupero dei dati da un sito con più provider di autenticazione mediante il modello a oggetti client e i servizi Web in SharePoint 2010
Articolo originale pubblicato sabato 2 aprile 2011
ll complesso titolo di questo post è appena un'indicazione del tema che tratteremo oggi. In questo post affronteremo infatti un problema che da tempo assilla non solo me. Ho iniziato a rifletterci poco tempo fa e, per pura coincidenza, ho poi ricevuto un messaggio di posta elettronica da un utente che aveva appena avuto informazioni su come risolverlo.
Di seguito mi concentrerò solo sugli aspetti più comuni di questo scenario, che può presentare numerose differenze da caso a caso. Il problema consiste nel recuperare dati da un sito di SharePoint in cui vengono utilizzati più provider di autenticazione. In questo scenario si presuppone che uno sia un provider di attestazioni di Windows e che l'altro sia di qualunque altro tipo, ad esempio un provider di autenticazione basata su moduli o di autenticazione SAML. Spesso si avrà la necessità di recuperare dati da tale sito utilizzando il modello a oggetti client oppure i servizi Web di SharePoint, ma alla fine si utilizzerà l'autenticazione di Windows. Il problema fino a questo punto è sempre stato, anche in caso di impostazione delle credenziali di Windows nella richiesta, la negazione dell'accesso al momento di richiedere i dati.
La soluzione del problema è la seguente: se si desidera accedere a livello di programmazione a un sito di SharePoint in cui vengono utilizzati più provider di autenticazione con un set di credenziali di Windows, è necessario aggiungere alla richiesta un'ulteriore intestazione. Il nome dell'intestazione deve essere X-FORMS_BASED_AUTH_ACCEPTED e il valore deve essere "f". L'aggiunta di tale intestazione non è un'attività particolarmente complessa per questi due scenari comuni, pertanto nel resto del post verrà illustrato come eseguirla con codice di esempio.
Se si utilizza il modello a oggetti client, sarà necessario aggiungere un gestore per l'evento ExecutingWebRequest. Di seguito è riportato un esempio del codice da utilizzare:
//create the client context
ClientContext ctx = new ClientContext(MixedUrlTxt.Text);
//configure the handler that will add the header
ctx.ExecutingWebRequest +=
new EventHandler<WebRequestEventArgs>(ctx_MixedAuthRequest);
//set windows creds
ctx.AuthenticationMode = ClientAuthenticationMode.Default;
ctx.Credentials = System.Net.CredentialCache.DefaultCredentials;
//get the web
Web w = ctx.Web;
//LOAD LISTS WITH ALL PROPERTIES
var lists = ctx.LoadQuery(w.Lists);
//execute the query
ctx.ExecuteQuery();
//enumerate the results
foreach (List theList in lists)
{
//do something with each list
}
E qui comincia la magia:
void ctx_MixedAuthRequest(object sender, WebRequestEventArgs e)
{
try
{
//add the header that tells SharePoint to use Windows Auth
e.WebRequestExecutor.RequestHeaders.Add(
"X-FORMS_BASED_AUTH_ACCEPTED", "f");
}
catch (Exception ex)
{
MessageBox.Show("Error setting auth header: " + ex.Message);
}
}
Ecco fatto. È tutto abbastanza semplice e non sono necessarie altre spiegazioni. La stessa attività con un riferimento a un servizio Web standard è leggermente diversa. Per iniziare, è opportuno esaminare il processo di aggiunta di un riferimento Web di stile standard di un sito di SharePoint a un progetto in Visual Studio 2010:
1. Fare clic con il pulsante destro del mouse sul nodo Riferimento al servizio e scegliere Aggiungi riferimento al servizio.
2. Fare clic sul pulsante Avanzate nella parte inferiore della finestra di dialogo.
3. Fare clic sul pulsante Aggiungi riferimento Web nella parte inferiore della finestra di dialogo successiva.
4. Immettere l'URL del servizio Web che si desidera utilizzare nella casella di modifica URL. Ad esempio, per aggiungere un riferimento al servizio Web Lists nel sito all'indirizzo https://foo, è possibile specificare quanto segue per l'URL: https://foo/_vti_bin/lists.asmx.
5. Premere INVIO o fare clic sul pulsante con la freccia verde per trovare il riferimento al servizio Web, quindi digitare un nome per tale riferimento nella casella di modifica Nome riferimento Web e fare clic sul pulsante Aggiungi riferimento.
Il riferimento e le relative classi proxy ora sono stati creati, ma è necessario aggiungere un'ulteriore classe parziale per aggiungere l'intestazione alla richiesta relativa al servizio Web. Iniziare aggiungendo una nuova classe al progetto e assegnarle il nome desiderato. Poiché si desidera semplicemente aggiungere un ulteriore comportamento (aggiungendo un'intestazione alla richiesta), è necessario trasformarla in una classe parziale. Questo significa che è necessario copiare lo spazio dei nomi e il nome di classe utilizzati nel proxy creato per il riferimento Web. Ecco i passaggi da eseguire:
1. Fare clic sul pulsante Mostra tutti i file nella finestra Esplora soluzioni di Visual Studio.
2. Fare clic sul segno più accanto al riferimento al servizio Web per espanderlo.
3. Fare clic sul segno più accanto al file Reference.map per espanderlo.
4. Fare doppio clic sul file Reference.cs per aprirlo.
5. Copiare lo spazio dei nomi e incollarlo nella propria classe.
6. Copiare il nome della classe, inclusa l'ereditarietà, e incollarlo nella propria classe come nome della classe. La classe relativa al riferimento al servizio Web è già una classe parziale, pertanto non è necessario apportare altre modifiche.
Di seguito è riportato un esempio della mia classe Reference.cs per il mio riferimento al servizio Web:
namespace ClientOmAuth.listsWS {
using System;
using System.Web.Services;
using System.Diagnostics;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Xml.Serialization;
/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Web.Services", "4.0.30319.1")]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(Name="ListsSoap", Namespace="https://schemas.microsoft.com/sharepoint/soap/")]
public partial class Lists : System.Web.Services.Protocols.SoapHttpClientProtocol {
Ed ecco quanto ho incollato nella classe che ho creato:
namespace ClientOmAuth.listsWS
{
public partial class Lists : System.Web.Services.Protocols.SoapHttpClientProtocol
{
}
}
È possibile notare che il nome dello spazio dei nomi e quello della classe corrispondono e che entrambe le classi ereditano dallo stesso tipo di base.
È ora necessario ignorare il metodo GetWebRequest in modo da poter aggiungere l'intestazione. A tale scopo, è sufficiente aggiungere il codice seguente alla propria classe parziale:
protected override System.Net.WebRequest GetWebRequest(Uri uri)
{
System.Net.WebRequest wr = null;
try
{
wr = base.GetWebRequest(uri);
wr.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
}
catch (Exception ex)
{
//some error handling here
}
return wr;
}
Il codice per recuperare i dati tramite il servizio Web ora è perfettamente identico a quello da utilizzare per qualsiasi sito di SharePoint con autenticazione di Windows:
//create the web service proxy and configure it use my Windows credentials
listsWS.Lists lws = new listsWS.Lists();
lws.UseDefaultCredentials = true;
//get the collection of lists
XmlNode xLists = lws.GetListCollection();
//enumerate results
foreach (XmlNode xList in xLists.ChildNodes)
{
//do something with each List
}
Non c'è altro da fare. È possibile applicare queste informazioni anche per recuperare dati tramite REST utilizzando le tecniche che ho descritto nel documento all'indirizzo seguente: https://blogs.technet.com/b/speschka/archive/2010/09/25/retrieving-rest-data-in-a-claims-based-auth-site-in-sharepoint-2010.aspx.
Questo è un post di blog localizzato. L'articolo originale è disponibile in Retrieving Data from a Multi Auth Site Using the Client OM and Web Services in SharePoint 2010.