Ottobre 2008
Introduzione
Pubblico
Questo articolo ti guiderà nella creazione di un gadget di Blogger. Presuppone che tu abbia familiarità con le API Google Data e con la libreria client JavaScript. Devi inoltre conoscere bene JavaScript e avere esperienza nell'implementazione di un gadget OpenSocial utilizzando gadgets.* API.
Questo esempio mostra anche come utilizzare correttamente le librerie esterne nei gadget. Ho utilizzato jQuery (principalmente per i suoi effetti UI) e TinyMCE, un ottimo plug-in di editor di testo RTF WYSIWYG.
Motivazione
Per creare un gadget che utilizza JSON con una delle API Google Data, è necessario un piccolo frammento di JavaScript. Il problema principale di questo gadget è che i dati
sono pubblici e di sola lettura. Per creare gadget più interessanti, devi accedere ai dati privati di un utente (un'operazione che richiede l'autenticazione). Finora non esisteva un modo efficace per sfruttare le API degli Account Google. AuthSub richiede reindirizzamenti del browser e
ClientLogin espone le credenziali di un utente lato client. Anche creare un gadget type="url"
è stato scomodo.
Inserisci il proxy OAuth.
Proxy OAuth
Se non hai familiarità con OAuth, si tratta di uno standard di autenticazione che consente a un utente di condividere i propri dati privati con un altro sito web o gadget. La specifica OAuth richiede che tutte le richieste di dati siano firmate digitalmente. Questo è ottimo per la sicurezza, ma nel caso di un gadget JavaScript, la gestione delle chiavi private e la creazione di firme digitali non è sicura. Inoltre, si aggiungono le complicazioni dei problemi interdominio.
Fortunatamente, questi problemi vengono risolti sfruttando una funzionalità della piattaforma dei gadget chiamata proxy OAuth. Il proxy OAuth è progettato per semplificare la vita degli sviluppatori di gadget. Nasconde gran parte dei dettagli di autenticazione di OAuth e fa il lavoro più pesante per te. Il proxy firma le richieste di dati per conto del gadget, quindi non è necessario gestire le chiavi private o preoccuparsi della firma delle richieste. È davvero semplice come sembra.
Il proxy OAuth è basato su un progetto open source chiamato Shindig, che è un'implementazione della specifica del gadget.
Nota: il proxy OAuth è supportato solo per i gadget che utilizzano l'API gadgets.*
e vengono eseguiti in contenitori OpenSocial.
Non è supportato per l'API gadget legacy.
Per iniziare
Il resto di questo tutorial si concentrerà sulla creazione di un gadget per accedere ai dati di Blogger di un utente. Vedremo l'autenticazione (utilizzando il proxy OAuth), l'utilizzo della libreria client JavaScript e, infine, la pubblicazione di una voce su Blogger.
Autenticazione
Innanzitutto, dobbiamo dire al gadget di utilizzare OAuth. Per farlo, aggiungi l'elemento <OAuth>
nella sezione <ModulePrefs>
del gadget:
<ModulePrefs> ... <OAuth> <Service name="google"> <Access url="https://www.google.com/accounts/OAuthGetAccessToken" method="GET" /> <Request url="https://www.google.com/accounts/OAuthGetRequestToken?scope=http://www.blogger.com/feeds/" method="GET" /> <Authorization url="https://www.google.com/accounts/OAuthAuthorizeToken? oauth_callback=http://oauth.gmodules.com/gadgets/oauthcallback" /> </Service> </OAuth> ... </ModulePrefs>
I tre endpoint URL nell'elemento <Service>
corrispondono agli endpoint del token OAuth di Google. Di seguito è riportata la spiegazione dei parametri di query:
scope
Questo parametro è obbligatorio nell'URL della richiesta. Il gadget potrà accedere solo ai dati dei
scope
utilizzati in questo parametro. In questo esempio, il gadget accederà a Blogger. Se il gadget deve accedere a più di un'API Google Data, concatena lescope
aggiuntive con un%20
. Ad esempio, se vuoi accedere sia a Calendar che a Blogger, imposta l'ambito suhttp://www.blogger.com/feeds/%20http://www.google.com/calendar/feeds/
.oauth_callback
Questo parametro è facoltativo nell'URL di autorizzazione. La pagina di approvazione OAuth reindirizzerà a questo URL dopo che l'utente avrà approvato l'accesso ai suoi dati. Puoi scegliere di omettere questo parametro, impostarlo sulla tua "pagina approvata" o, preferibilmente, utilizzare
http://oauth.gmodules.com/gadgets/oauthcallback
. Il secondo offre la migliore esperienza utente quando gli utenti installano per la prima volta il gadget. Questa pagina fornisce uno snippet di JavaScript che chiude automaticamente la finestra popup.
Ora che il gadget utilizza OAuth, l'utente deve approvare l'accesso ai suoi dati. Ecco il flusso di autenticazione:
- Il gadget viene caricato per la prima volta e tenta di accedere ai dati Blogger dell'utente.
- La richiesta non va a buon fine perché l'utente non ha concesso l'accesso al gadget. Fortunatamente, l'oggetto restituito nella risposta
contiene un URL (
response.oauthApprovalUrl
) a cui invieremo l'utente per l'accesso. Il gadget mostra il messaggio "Accedi a Blogger" e imposta il relativo href sul valore dioauthApprovalUrl
. - Successivamente, l'utente fa clic su "Accedi a Blogger" e la pagina di approvazione OAuth si apre in una finestra separata. Il gadget attende che l'utente completi la procedura di approvazione visualizzando un link: "Ho approvato l'accesso".
- Nel popup, l'utente sceglierà se concedere o negare l'accesso al nostro gadget. Dopo aver fatto clic su "Concedi accesso", l'utente viene reindirizzato a
http://oauth.gmodules.com/gadgets/oauthcallback
e la finestra si chiude. - Il gadget riconosce la finestra chiusa e tenta di accedere a Blogger una seconda volta richiedendo nuovamente i dati dell'utente. Per rilevare la chiusura della finestra, ho utilizzato un gestore popup. Se non utilizzi questo codice, l'utente può fare clic manualmente su "Ho approvato l'accesso".
- Il gadget ora mostra la sua normale UI. Questa visualizzazione verrà mantenuta a meno che il token di autenticazione non venga revocato in IssuedAuthSubTokens.
Quindi, dai passaggi precedenti, i gadget hanno la nozione di tre stati diversi:
- Non autenticato. L'utente deve avviare la procedura di approvazione.
- In attesa che l'utente approvi l'accesso ai suoi dati.
- Autenticato. Il gadget mostra il suo normale stato di funzionamento.
Nel mio gadget, ho utilizzato <div>
contenitori per separare ogni fase:
<Content type="html"> <![CDATA[ <!-- Normal state of the gadget. The user is authenticated --> <div id="main" style="display:none"> <form id="postForm" name="postForm" onsubmit="savePost(this); return false;"> <div id="messages" style="display: none"></div> <div class="selectFeed">Publish to: <select id="postFeedUri" name="postFeedUri" disabled="disabled"><option>loading blog list...</option></select> </div> <h4 style="clear:both">Title</h4> <input type="text" id="title" name="title"/> <h4>Content</h4> <textarea id="content" name="content" style="width:100%;height:200px;"></textarea> <h4 style="float:left;">Labels (comma separated)</h4><img src="blogger.png" style="float:right"/> <input type="text" id="categories" name="categories"/> <p><input type="submit" id="submitButton" value="Save"/> <input type="checkbox" id="draft" name="draft" checked="checked"/> <label for="draft">Draft?</label></p> </form> </div> <div id="approval" style="display: none"> <a href="#" id="personalize">Sign in to Blogger</a> </div> <div id="waiting" style="display: none"> <a href="#" id="approvalLink">I've approved access</a> </di <!-- An errors section is not necessary but great to have --> <div id="errors" style="display: none"></div> <!-- Also not necessary, but great for informing users --> <div id="loading"> <h3>Loading...</h3> <p><img src="ajax-loader.gif"></p> </div> ]]> </Content>
Ogni <div>
viene visualizzato singolarmente utilizzando showOnly()
. Per informazioni dettagliate su questa funzione, consulta il gadget di esempio completo.
Utilizzo della libreria client JavaScript
Per recuperare contenuti remoti in OpenSocial, effettua una chiamata al metodo gadgets.io.makeRequest
utilizzando l'API gadgets.*
.
Tuttavia, poiché stiamo creando un gadget Google Data, non è necessario utilizzare le API gadgets.io.*
. Utilizza invece la libreria client JavaScript, che dispone di metodi speciali per effettuare richieste a ogni servizio Google Data.
Nota: al momento della stesura di questo articolo, la libreria JavaScript supporta solo Blogger, Calendar,
Contatti,
Finanza e Google Base. Per utilizzare una delle altre
API, utilizza gadgets.io.makeRequest
senza la libreria.
Caricamento della libreria
Per caricare la libreria JavaScript, includi il caricatore comune nella sezione <Content>
e importa la libreria
una volta inizializzato il gadget. L'invio di un callback a gadgets.util.registerOnLoadHandler()
aiuterà a determinare quando il gadget è pronto:
<Content type="html"> <![CDATA[ ... <script src="https://www.google.com/jsapi"></script> <script type="text/javascript"> var blogger = null; // make our service object global for later // Load the JS library and try to fetch data once it's ready function initGadget() { google.load('gdata', '1.x', {packages: ['blogger']}); // Save overhead, only load the Blogger service google.setOnLoadCallback(function () { blogger = new google.gdata.blogger.BloggerService('google-BloggerGadget-v1.0'); blogger.useOAuth('google'); fetchData(); }); } gadgets.util.registerOnLoadHandler(initGadget); </script> ... ]]> </Content>
La chiamata a blogger.useOAuth('google')
indica alla libreria di utilizzare il proxy OAuth (anziché AuthSubJS, il suo normale metodo di autenticazione).
Infine, il gadget tenta di recuperare i dati di Blogger dell'utente chiamando fetchData()
. Questo metodo è definito di seguito.
Recupero dati
Ora che tutto è configurato, come facciamo a GET
o POST
i dati su Blogger?
Un paradigma comune in OpenSocial è definire una funzione chiamata fetchData()
nel gadget. Questo metodo in genere gestisce le diverse fasi dell'autenticazione e recupera i dati utilizzando gadgets.io.makeRequest
. Poiché utilizziamo la libreria client JavaScript, gadgets.io.makeRequest
viene sostituito da una chiamata a blogger.getBlogFeed()
:
function fetchData() { jQuery('#errors').hide(); var callback = function(response) { if (response.oauthApprovalUrl) { // You can set the sign in link directly: // jQuery('#personalize').get(0).href = response.oauthApprovalUrl // OR use the popup.js handler var popup = shindig.oauth.popup({ destination: response.oauthApprovalUrl, windowOptions: 'height=600,width=800', onOpen: function() { showOnly('waiting'); }, onClose: function() { showOnly('loading'); fetchData(); } }); jQuery('#personalize').get(0).onclick = popup.createOpenerOnClick(); jQuery('#approvalLink').get(0).onclick = popup.createApprovedOnClick(); showOnly('approval'); } else if (response.feed) { showResults(response); showOnly('main'); } else { jQuery('#errors').html('Something went wrong').fadeIn(); showOnly('errors'); } }; blogger.getBlogFeed('http://www.blogger.com/feeds/default/blogs', callback, callback); }
La seconda volta che viene chiamata questa funzione, response.feed
contiene dati.
Nota: getBlogFeed()
utilizza la stessa funzione per il callback e il gestore degli errori.
Pubblicare una voce su Blogger
L'ultimo passaggio consiste nel pubblicare una nuova voce in un blog. Il codice riportato di seguito mostra cosa succede quando l'utente fa clic sul pulsante "Salva".
function savePost(form) { jQuery('#messages').fadeOut(); jQuery('#submitButton').val('Publishing...').attr('disabled', 'disabled'); // trim whitespace from the input tags var input = form.categories.value; var categories = jQuery.trim(input) != '' ? input.split(',') : []; jQuery.each(categories, function(i, value) { var label = jQuery.trim(value); categories[i] = { scheme: 'http://www.blogger.com/atom/ns#', term: label }; }); // construct the blog post entry var newEntry = new google.gdata.blogger.BlogPostEntry({ title: { type: 'text', text: form.title.value }, content: { type: 'text', text: form.content.value }, categories: categories }); // publish as draft? var isDraft = form.draft.checked; if (isDraft) { newEntry.setControl({draft: {value: google.gdata.Draft.VALUE_YES}}); } // callback for insertEntry() var handleInsert = function(entryRoot) { var entry = entryRoot.entry; var str = isDraft ? '(as draft)' : '<a href="' + entry.getHtmlLink().getHref() + '" target="_blankt">View it</a>'; jQuery('#messages').html('Post published! ' + str).fadeIn(); jQuery('#submitButton').val('Save').removeAttr('disabled'); }; // error handler for insertEntry() var handleError = function(e) { var msg = e.cause ? e.cause.statusText + ': ' : ''; msg += e.message; alert('Error: ' + msg); }; blogger.insertEntry(form.postFeedUri.value, newEntry, handleInsert, handleError); }
Conclusione
Ora hai i componenti di base per iniziare a programmare un gadget basato sulle API Google Data.
Ci auguriamo che questo articolo ti abbia fatto capire quanto OAuth Proxy semplifichi l'autenticazione dei gadget. La combinazione di questo potente strumento con la libreria client JavaScript di Google Data semplifica la creazione di gadget interessanti, interattivi e sofisticati.
Se hai domande o commenti su questo articolo, visita il forum di discussione sulle API Google Accounts.
Risorse
- Scrittura di gadget OAuth (documentazione completa sui gadget)
- Utilizzo di OAuth con le API Google Data (articolo sull'utilizzo di OAuth con le API Google Data)
- Autenticazione OAuth per applicazioni web (documentazione completa di OAuth)
- Libreria client JavaScript
- Forum di discussione delle API Google Accounts