xscDevBlog – LastSharp & Co.

Der xscheme-DevelopmentBlog

Inside Last.FM: Silent Authentication für API 2.0

with one comment

Update (17.07.2009): Das hier ist (abgesehen von den “Skills”, die ich dabei gebraucht hab) wohl ziemlich überflüssig, wenn man die API-Methode auth.getMobileSession mal genauer betrachtet. Wieder was gelernt: RTFM!

Da im Moment anscheinend wieder Änderungen am Last.FM-Webservice gemacht werden, die dazu geführt haben, dass LastSharp höchstens noch mithilfe der “Modifizierten Verbindung” (unter “Erweiterte Einstellungen” >> “Verschiedenes”) funktioniert, habe ich mir mal das Radio-API angesehen, das ja anscheinend die Zukunft des Radiostreamings bei Last.FM ist. Was mich daran allerdings stört, ist die umständliche Anmeldeprozedur: Token holen, Browser öffnen, auf Authentifizierung warten, Session holen.

Der Umweg über den Browser ist einfach unschön, weshalb ich nach einer Lösung gesucht habe, die den Login sowie die anschließende Bestätigung eines Users im Hintergrund simuliert, sodass er das eigentliche Programm nicht verlassen muss.

Funktionen, die Authentication-Token und -Session holen, werden im folgenden als gegeben betrachetet, z.B. durch LastFmLib.Net.

Wir brauchen nun also zwei Funktionen, die das Abschicken des Login-Formulars und das Klicken auf den “Zulassen”-Button vortäuschen. Beide Operationen produzieren eine HTTP-POST-Anfrage, funktionieren aber nur, wenn auch die richtigen Cookies vorhanden sind. (Das hat mich einige Zeit gekostet und dabei war die Lösung so einfach…) Es bietet sich an, die POST-Anfrage in eine Hilfsfunktion ExecutePOST zu packen, hier z.B. in C#:
(Namespace System.Net muss eingebunden sein)

// Löst das Cookie Problem: Immer denselben Container verwenden!
private static CookieContainer GlobalCookies = new CookieContainer();

// Sendet eine POST-Anfrage
public static void ExecutePOST(string uri, string data) {
    try
    {
        // Bereite die Anfrage vor
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
        request.Method = "POST";
        request.CookieContainer = GlobalCookies; // !!
        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = data.Length;

        // Schreiben der Daten
        ASCIIEncoding enc = new ASCIIEncoding();
        byte[] bdata = enc.GetBytes(bodyData);
        Stream str = req.GetRequestStream();
        str.Write(bdata, 0, bdata.Length);
        str.Close();

        // Schicke Anfrage ab und verwirf die Antwort
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        response.Close();
    }
    catch { }
}

Will man überprüfen, ob die gewünschte Operation erfolgreich war, würde es sich vermutlich anbieten, die Antwort auszuwerten, aber darauf verzichte ich jetzt aus Zeitgründen.

Nächster Schritt ist die Untersuchung der Formulare auf der Last.FM-Seite, damit man weiß, welche Daten an welche Adresse gesendet werden müssen:

  • Login: https://www.last.fm/login/
    • refererKey (leer)
    • backto (“/”)
    • username (Benutzername)
    • password (Passwort)
  • Zulassen: http://www.last.fm/api/grantAccess
    • api_key (Last.FM schickt den sogar zweimal, wir deshalb sicherheitshalber auch…)
    • token (Authentication-Token)
    • referer (“/”)

Also, die beiden verbleibenden Funktionen in C#:

    // Lasse ein Programm zu
    public static void GrantAccess(string token)
    {
        ExecutePOST(
            "http://www.last.fm/api/grantAccess",
            "api_key=" + apiKey + "&api_key=" + apiKey + "&token=" + token + "&referer=/"
        );
    }

    // Melde den User bei Last.FM an
    public static void Login(string username, string password)
    {
        ExecutePOST(
            "https://www.last.fm/login/",
            "refererKey=&backto=/&username=" + Uri.EscapeDataString(username) +
            "&password=" + Uri.EscapeDataString(password)
        );
    }

Um jetzt eine gesamte Anmeldung zu simulieren, müsste man nun folgendes machen:

public static void Authenticate(string username, string password)
{
    string token = GetToken(); // irgendeine externe Funktion
    Login(username, password);
    GrantAccess(token);
    string session = GetSession(); // irgendeine externe Funktion
    // Mache etwas...
}

Das war’s auch schon. Wie gesagt fehlt hier ein Test, ob die Anmeldung erfolgreich war, aber irgendwie lässt sich das bestimmt einfach überprüfen. (Vllt. liefert Last.FM ja im Hintergrund einen HTTP-Error, der im Browser nicht auffällt?)

Jedenfalls, wenn jemand die Authentifizierung für das Last.FM-API 2.0 im Hintergrund ablaufen lassen will, ist das hier der Weg. Ich hoffe, es hilft.

Die Verwendung des Radio-APIs in LastSharp werde ich übrigens so lang wie möglich hinauszögern, da hier wieder einmal diverse Standards (HTTP, XML, …) unsachgemäß ausgelegt werden…

Written by

Juli 8th, 2009 at 11:47 pm

Posted in C#, General, Lapicon, Web

Tagged with

One Response to 'Inside Last.FM: Silent Authentication für API 2.0'

Subscribe to comments with RSS or TrackBack to 'Inside Last.FM: Silent Authentication für API 2.0'.

  1. Hallo,

    die modifizierte Verbdinung mag leider auch nicht mehr funktionieren…

    Viele Grüße,
    Stefan

    Stefan

    9 Jul 09 at 08:34

Leave a Reply