Home > Web Entwicklung > Opensocial Gadgets – Apps für StudiVZ selbst entwickeln

Opensocial Gadgets – Apps für StudiVZ selbst entwickeln

Wie StudiVZ bereits angekündigt hat, werden die ersten opensocial Anwendungen für ihre Plattform bald live gehen. Entwickler können sich schon jetzt registrieren und ihre so genannten Gadgets in einer Sandbox ausprobieren.

Ich habe das Vergnügen für meinen aktuellen Kunden DaWanda ein Gadget für StudiVZ zu entwickeln. Ein Gadget besteht aus einer XML Datei, die definiert, um welche Anwendung es sich handelt, wer der Author ist usw. Dazu gehören wahlweise mehrere CSS und Javascript Dateien. Nachdem man alles in eine Zip Datei, die den gleichen namen wie die XML Datei trägt, gepackt hat, kann man die Anwendung in die Sandbox hochladen und ausprobieren. Eine Beispiel Datei könnte so aussehen:

<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs
    title="Example StudiVZ Gadget"
    title_url="http://www.christophbuente.de"
    author="Christoph Bünte"
    author_email="info@christophbuente.de"
    description="Example description"
    screenshot="http://www.christophbuente.de/images/screenshot.jpg"
    thumbnail="http://www.christophbuente.de/images/thumbnail.jpg">
    <Require feature="opensocial-0.8" />
    <Require feature="views" />
  </ModulePrefs>
  <Content type="html" >
    <![CDATA[
      <script>
        function init() {
          // Put initialization code here
        }
        gadgets.util.registerOnLoadHandler(init);
      </script>
    <div id='container'></div>
    ]]>
  </Content>
</Module>


Jede Interaktion des Benutzers mit der Anwendung wird mit Hilfe weiterer Javascript Funktionen behandelt. Dazu stehen eine Reihe eingebauter Funktionen aus dem Opensocial Container bereit. Darüber hinaus haben die Entwickler von StudiVZ eine API Beschreibung der zusätzlichen Funktionen bereit gestellt. Was aber, wenn man nun nicht mit Javascript entwickeln möchte bzw. kann? Es besteht die Möglichkeit Flash Content einzubinden. Man kann aber auch ein beliebiges Backend einbinden. Dieses Backend muss nur 2 Bedingungen erfüllen:

  • Es muss auf HTTP Requests reagieren können und beliebiges HTML,CSS und JavaScript zurück liefern
  • Es muss im Namen des Applikationsbenutzers einen OAuth signierten Request an die StudiVZ REST API schicken können.

Schema: Request Opensocial Backend
Wie im Schema zu sehen, sendet der User einen Request, um die Applikation zu benutzen. Der Container liest darauf hin den Inhalt der XML Datei aus. Dort ist neben einem DIV Container lediglich ein externes Javascript referenziert. In dem Javascript sind einfache Methoden zum Navigieren und Interagieren definiert. Das rendern des HTML übernimmt ein Ruby Backend. Das braucht zum Render unter Umständen noch zusätzliche Informationen wie zum Beispiel Name und Foto des Benuter usw. Diese Informationen holt es sich mit einem OAuth signierten Request von der abgebildeten REST API. Das vom Ruby Backend erzeugte HTML rendert der Opensocial Container in einem IFrame im Browser des Benutzers. Für eine bessere Übersicht definieren wir im XML einzelne Views, die jeweils einen eigenen Endpunkt im Backend haben. Eine einfache gadget.xml mit 2 definierten Views für Profil und Vollansicht mit Backend Anbindung:

<?xml version="1.0" encoding="UTF-8"?>
<Module>
  <ModulePrefs
    title="Spitzenmässiges StudiVZ Gadget mit Backendanbindung"
    title_url="http://www.christophbuente.de"
    author="Christoph Bünte"
    author_email="info@christophbuente.de">
    <Require feature="opensocial-0.8" />
    <Require feature="views" />
  </ModulePrefs>
  <Content type="html" view="profile" >
    <![CDATA[
      <script type="text/javascript" src="http://www.yourbackend.com/profile.js" ></script>
      <div id='profile'></div>
    ]]>
  </Content>
  <Content type="html" view="canvas" >
    <![CDATA[
      <script type="text/javascript" src="http://www.yourbackend.com/canvas.js" ></script>
      <div id='canvas'></div>
    ]]>
  </Content>
</Module>

Das referenzierte Javascript ist ebenfalls sehr schlank. Darin wird lediglich eine Backend URL aufgerufen und deren Response Body in das profile bzw. canvas div geschrieben.

function init{
  var url = 'http://www.yourbackend.com/profile/'
  var params = {};
  params[gadgets.io.RequestParameters.AUTHORIZATION]=gadgets.io.AuthorizationType.SIGNED;
  gadgets.io.makeRequest(url, requestCallback, params);

}

function requestCallback(obj) {
	document.getElementById('profile').innerHTML = obj.data;
}

Damit die REST API benutzt werden kann, muss man sich an ihr Authentifizieren. Da das Backend aber dumm ist, hat es keine Userdaten, um sich dort anzumelden. Glücklicherweise ist der Request aus dem Javascript mit dem verschlüsselten Authentifierungsdaten des angemeldeten Anwendungsbenutzers signiert. Mit deren Hilfe können wir einen neuen, signierten Request erzeugen, den die API akzeptieren wird. Doch zuerst muss die Glültigkeit der Signatur überprüft werden:

sudo gem install oauth --source http://gemcutter.org

require 'oauth'
require 'oauth/consumer'
require 'oauth/request_proxy/action_controller_request'
require 'oauth/signature/rsa/sha1'
require 'oauth/signature/hmac/sha1'

class ApplicationController < ActionController::Base

  before_filter :oauth_required

  def oauth_required
    cert_file = File.join(RAILS_ROOT, 'public', 'public.cer')
    cert_str = File.read(cert_file)
    consumer = OAuth::Consumer.new(ConsumerToken, cert_str)
    
    begin
      pass = OAuth::Signature.build(request, :consumer => consumer).verify
      logger.info "Signature verification returned: #{pass}"
    rescue OAuth::Signature::UnknownSignatureMethod => e
      logger.error "ERROR "+ e.message
    end
    
    render :text => "OAuth access denied", :status => :unauthorized  unless pass
  end

Die URL für das öffentliche Zertifikat wird mit jedem Request mit geschickt. Einmal runterladen sollte reichen. Ich denke, man muss es nicht bei jedem Request erneut vom StudiVZ Server laden. Den Consumer Token findet ihr in der OAuth Section eurer Gadget Sandbox (http://www.meinvz.net/GadgetDeveloper/GadgetOAuth/xxx). xxx ist deine Gadget ID.

Sollte der before_filter nicht abbrechen war die Signatur korrekt und der Request kann bearbeitet werden. Aus einem mir nicht bekannten Grund ist der Request des Containers an das Backend mit der RSA-SHA1 Methode signiert. Dafür wird das Zertifikat benötigt. Für den Request an die API muss die HMAC-SHA1 Methode verwendet werden. Dafür wird ein neuer Consumer benötigt:

def get_owner
  consumer = OAuth::Consumer.new(ConsumerToken, ConsumerSecret, 
      :signature_method => 'HMAC-SHA1',
      :site => "http://sandbox.gadgets.apivz.net",
      :scheme => :query_string,
      :http_method => :get)
  requestor_param = {:xoauth_requestor_id => params[:opensocial_owner_id]}.to_param
  access_token = OAuth::AccessToken.new(consumer)
  response = access_token.get("/social/rest/people/#{params[:opensocial_owner_id]}/@self?#{requestor_param}")
  owner_attributes = JSON.parse(response.body)['entry']
end

Feedback, Fragen und Kritik sind immer gerne willkommen.

  1. 30. Oktober 2009, 17:35 | #1

    Wow, vielen Dank Christoph! Ein guter Startpunkt erstmal, habe nämlich das Gleiche vor für meinen Kunden ;-) Hab dich gar nicht auf der studiVz geek night getroffen. Nicht dass du was versäumt hättest :-)

  2. 30. Oktober 2009, 17:42 | #2

    Ich war auch nicht da. Bin zu der Gadget Nummer gekommen wie die Jungfrau zum Kinde. :) Und ich habe 2 Tage lang geflucht, um das alles rauszukriegen. War sehr mühselig.

    Kein OAuth Tutorial, was ich gefunden habe zeigt dir, daß du das Zertifikat für die Signaturprüfung verwenden musst, sondern immer nur das Secret. Erst die genaue Analyse samt HTTP Sniffer haben ans Tageslicht gebracht, daß du die OAuth parameter an die URL anhängen musst, und nicht in den Header schreibst.

    Ich hoffe ich hab Dir ein wenig Arbeit und Frust gespart.

  3. 27. November 2009, 14:15 | #3

    Hi!

    Tausend dank für diesen Beitrag, das erspart mir gerade eine Menge Arbeit und auch reichlich Nerven ;-)
    Ich hab’s soweit implementiert, aber mal sehen ob es auch beim Test gleich funktioniert.

    Kleine Ergänzung:
    Die Zertifikate bekommt man im Übrigen auch hier http://developer.studivz.net/wiki/index.php/Gadgets.io_%28v0.8%29#Key_management_for_gadgets.io.AuthorizationType.SIGNED So muss man sie nicht aus dem Request fischen :)

    VG,
    Christopher

  4. 16. Dezember 2009, 20:53 | #4

    Danke für deinen Artikel. Hilft mir sehr bei der Gadget Entwicklung. Die VZ-Doku ist ja noch eine Karte voller weißer Flecken…

  1. 18. Januar 2010, 10:53 | #1