OAuth mit Verifizierung in .NET

Ich versuche, eine .NET-basierte Client-App zu erstellen (in WPF – obwohl ich es gerade als Konsolen-App mache), um eine OAuth-fähige Anwendung zu integrieren, speziell Mendeley ( http://dev.microsoft.com/en-us/library/) .mendeley.com ), die offensichtlich 3-beinigen OAuth verwendet.

Dies ist das erste Mal, dass ich OAuth benutze und ich habe große Schwierigkeiten, damit anzufangen. Ich habe mehrere .NET OAuth-Bibliotheken oder -Helfer gefunden, aber sie scheinen komplizierter zu sein, als ich denke. Ich möchte lediglich REST-Anfragen an die Mendeley-API senden und Antworten erhalten!

Bisher habe ich es versucht:

  • DotNetOpenAuth
  • http://github.com/bittercoder/DevDefined.OAuth
  • http://oauth.googlecode.com/svn/code/csharp/

Der erste (DotNetOpenAuth) scheint so zu sein, als könnte er das tun, was ich brauchte, wenn ich Stunden damit zubringen würde, herauszufinden, wie. Der zweite und der dritte unterstützen, soweit ich das beurteilen kann, nicht die Bestätigungscodes, die Mendeley zurücksendet – obwohl ich mich dabei irren könnte 🙂

Ich habe einen Kundenschlüssel und ein Geheimnis von Mendeley, und mit DotNetOpenAuth habe ich es geschafft, einen Browser mit der Mendeley-Seite zu starten, der einen Bestätigungscode für den Benutzer bereitstellt, um in die Anwendung einzutreten. An diesem Punkt habe ich mich jedoch verirrt und konnte nicht herausfinden, wie ich das vernünftig zurück zur Anwendung bringen kann.

Ich bin sehr bereit zuzugeben, dass ich keine Ahnung habe, wo ich damit anfangen soll (obwohl es scheint, als ob es eine ziemlich steile Lernkurve gibt) – wenn mir jemand in die richtige Richtung zeigen könnte, würde ich es begrüßen!

   

Ich stimme dir zu. Die Open-Source-OAuth-Supportklassen, die für .NET-Anwendungen verfügbar sind, sind schwer zu verstehen, zu kompliziert (wie viele Methoden werden von DotNetOpenAuth bereitgestellt?), Schlecht entworfen (sehen Sie sich die Methoden mit 10 String-Parametern im Modul OAuthBase.cs von diesem Google an) Link Sie zur Verfügung gestellt – es gibt überhaupt keine staatliche Verwaltung), oder sonst unbefriedigend.

Es muss nicht so kompliziert sein.

Ich bin kein Experte für OAuth, aber ich habe eine Client-seitige OAuth-Manager-class erstellt, die ich erfolgreich mit Twitter und TwitPic verwende. Es ist relativ einfach zu bedienen. Es ist Open Source und hier verfügbar: Oauth.cs

Zur Überprüfung, in OAuth 1.0a … irgendwie lustig, es gibt einen speziellen Namen und es sieht aus wie ein “Standard”, aber soweit ich weiß ist der einzige Dienst, der “OAuth 1.0a” implementiert, Twitter. Ich denke, das ist Standard genug . OK, in OAuth 1.0a funktioniert das für Desktop-Apps wie folgt:

  1. Sie, der Entwickler der App, registrieren die App und erhalten einen “Consumer Key” und “Consumer Secret”. Auf der Arstechnica gibt es eine gut geschriebene Analyse, warum dieses Modell nicht das beste ist , aber wie es heißt, ist es das, was es ist .

  2. Ihre App wird ausgeführt. Bei der ersten Ausführung muss der Benutzer explizit zulassen, dass die App Oauth-authentifizierte REST-Anforderungen an Twitter und seine Schwesterdienste (wie TwitPic) sendet. Dazu müssen Sie einen Genehmigungsprozess durchlaufen, der eine ausdrückliche Genehmigung des Benutzers beinhaltet. Dies geschieht nur beim ersten Start der App. So was:

    • Fordern Sie ein “Anfrage-Token” an. Aka temporäres Token.
    • Öffnen Sie eine Webseite und übergeben Sie dieses Anforderungs-Token als Abfrageparameter. Diese Webseite zeigt dem Benutzer die Benutzeroberfläche mit der Frage “Möchten Sie dieser App Zugriff gewähren?”
    • Der Benutzer meldet sich auf der Twitter-Webseite an und gewährt oder verweigert den Zugriff.
    • Die Antwort-HTML-Seite erscheint. Wenn der Benutzer Zugriff gewährt hat, wird eine PIN in einer 48-pt-Schriftart angezeigt
    • Der Benutzer muss nun diesen Stift in ein Windows-Formularfeld ausschneiden und einfügen und auf “Weiter” oder Ähnliches klicken.
    • Die Desktop-App führt dann eine oauth-authentifizierte Anfrage für ein “Access-Token” durch. Eine weitere REST-Anfrage
    • Die Desktop-App erhält das “Access Token” und “Access Secret”.

Nach dem Genehmigungstanz kann die Desktop-App einfach das benutzerspezifische “Zugriffstoken” und “Zugriffsgeheimnis” (zusammen mit dem anwendungsspezifischen “Konsumentenschlüssel” und “Konsumentengeheimnis”) verwenden, um authentifizierte Anfragen im Auftrag des Benutzers auszuführen zu Twitter. Diese laufen nicht ab, obwohl, wenn der Benutzer die App ent-autorisiert oder wenn Twitter aus irgendeinem Grund Ihre App ent-autorisiert, oder wenn Sie Ihr Zugangstoken und / oder -geheimnis verlieren, müssen Sie den Genehmigungstanz erneut durchführen .


Wenn Sie nicht clever sind, kann der UI-Fluss den mehrstufigen OAuth-Nachrichtenfluss spiegeln. Es gibt einen besseren Weg.

Verwenden Sie ein WebBrowser-Steuerelement, und öffnen Sie die Autorisieren-Webseite in der Desktop-App. Wenn der Benutzer auf “Zulassen” klickt, den Antworttext aus diesem WebBrowser-Steuerelement abrufen, die PIN automatisch extrahieren und dann die Zugriffstoken abrufen. Sie senden 5 oder 6 HTTP-Anfragen, aber der Benutzer muss nur einen einzigen Dialog Erlauben / Verweigern sehen. Einfach.

So was:
Alt-Text


Wenn Sie die Benutzeroberfläche sortiert haben, besteht die einzige Herausforderung darin, oauth-signierte Anfragen zu erstellen. Dies stolpert viele Leute, weil die oauth Signierungsanforderungen eine Art besonderer sind. Das macht die vereinfachte OAuth-Manager-class.

Beispielcode zum Anfordern eines Tokens:

var oauth = new OAuth.Manager(); // the URL to obtain a temporary "request token" var rtUrl = "https://api.twitter.com/oauth/request_token"; oauth["consumer_key"] = MY_APP_SPECIFIC_KEY; oauth["consumer_secret"] = MY_APP_SPECIFIC_SECRET; oauth.AcquireRequestToken(rtUrl, "POST"); 

Das ist es . Einfach. Wie Sie aus dem Code sehen können, ist der Weg zu oauth-Parametern über einen String-basierten Indexer, etwa ein Wörterbuch. Die AcquireRequestToken-Methode sendet eine oauth-signierte Anforderung an die URL des Dienstes, der Anfragetoken, auch temporäre Token genannt, zulässt. Für Twitter lautet diese URL ” https://api.twitter.com/oauth/request_token “. Die oauth-Spezifikation besagt, dass Sie die oauth-Parameter (token, token_secret, nonce, timestamp, consumer_key, version und callback) in einer bestimmten Weise (url-codiert und von Et-Zeichen) und in einem lexikographisch- sortierte Reihenfolge, generieren Sie eine Signatur für dieses Ergebnis und packen Sie dann dieselben Parameter zusammen mit der Signatur, die im neuen Parameter oauth_signature gespeichert ist, auf andere Weise (durch Kommas verbunden). Die OAuth-Manager-class erledigt dies automatisch für Sie. Es generiert automatisch Nonces und Zeitstempel sowie Versionen und Signaturen – Ihre App muss sich nicht darum kümmern oder sich dessen bewusst sein. Setzen Sie einfach die OAuth-Parameterwerte und führen Sie einen einfachen Methodenaufruf durch. Die Manager-class sendet die Anfrage und analysiert die Antwort für Sie.

OK was dann? Sobald Sie das Anforderungstoken erhalten haben, rufen Sie die Benutzeroberfläche des Webbrowsers auf, in der der Benutzer explizit die Genehmigung erteilen wird. Wenn Sie es richtig machen, werden Sie dies in einem eingebetteten Browser anzeigen. Für Twitter lautet die URL ” https://api.twitter.com/oauth/authorize?oauth_token= ” mit angehängtem oauth_token. Tun Sie das in Code wie folgt:

 var url = SERVICE_SPECIFIC_AUTHORIZE_URL_STUB + oauth["token"]; webBrowser1.Url = new Uri(url); 

(Wenn Sie dies in einem externen Browser tun würden, würden Sie System.Diagnostics.Process.Start(url) .)

Wenn Sie die URL-Eigenschaft festlegen, navigiert das WebBrowser-Steuerelement automatisch zu dieser Seite.

Wenn der Benutzer auf die Schaltfläche “Zulassen” klickt, wird eine neue Seite geladen. Es ist ein HTML-Formular und es funktioniert genauso wie in einem vollständigen Browser. Registrieren Sie in Ihrem Code einen Handler für das DocumenedCompleted-Ereignis des WebBrowser-Steuerelements, und greifen Sie in diesem Handler auf den Pin:

 var divMarker = "
"; // the div for twitter's oauth pin var index = webBrowser1.DocumentText.LastIndexOf(divMarker) + divMarker.Length; var snip = web1.DocumentText.Substring(index); var pin = RE.Regex.Replace(snip,"(?s)[^0-9]*([0-9]+).*", "$1").Trim();

Das ist ein bisschen HTML-Scraping.

Nachdem Sie den Pin gegriffen haben, brauchen Sie den Webbrowser nicht mehr, also:

 webBrowser1.Visible = false; // all done with the web UI 

… und Sie möchten vielleicht auch Dispose () aufrufen.

Der nächste Schritt ist das Abrufen des Zugriffstokens durch Senden einer weiteren HTTP-Nachricht zusammen mit diesem Pin. Dies ist ein weiterer signierter OAUTH-Aufruf, der mit der oben beschriebenen OAUTH-Reihenfolge und -Formatierung erstellt wurde. Aber das ist mit der OAuth.Manager-class noch einmal ganz einfach:

 oauth.AcquireAccessToken(URL_ACCESS_TOKEN, "POST", pin); 

Für Twitter lautet diese URL ” https://api.twitter.com/oauth/access_token “.

Jetzt haben Sie Zugriffstoken und Sie können sie in signierten HTTP-Anfragen verwenden. So was:

 var authzHeader = oauth.GenerateAuthzHeader(url, "POST"); 

… wobei url der Ressourcenendpunkt ist. Um den Status des Benutzers zu aktualisieren, wäre es ” http://api.twitter.com/1/statuses/update.xml?status=Hello “.

Setzen Sie diese Zeichenfolge dann in den HTTP-Header namens Autorisierung .

Um mit Diensten von Drittanbietern, wie TwitPic, zu interagieren, müssen Sie einen etwas anderen OAuth-Header wie folgt erstellen:

 var authzHeader = oauth.GenerateCredsHeader(URL_VERIFY_CREDS, "GET", AUTHENTICATION_REALM); 

Für Twitter lauten die Werte für die URL und den Realm für die Überprüfung von Krediten ” https://api.twitter.com/1/account/verify_credentials.json ” bzw. ” http://api.twitter.com/ “.

… und setze diese Autorisierungszeichenfolge in einen HTTP-Header namens X-Verify-Credentials-Authorization . Dann senden Sie das wie TwitPic zusammen mit Ihrer Anfrage an Ihren Dienst.

Das ist es.

Alles in allem könnte der Code zum Aktualisieren des Twitter-Status etwa so aussehen:

 // the URL to obtain a temporary "request token" var rtUrl = "https://api.twitter.com/oauth/request_token"; var oauth = new OAuth.Manager(); // The consumer_{key,secret} are obtained via registration oauth["consumer_key"] = "~~~CONSUMER_KEY~~~~"; oauth["consumer_secret"] = "~~~CONSUMER_SECRET~~~"; oauth.AcquireRequestToken(rtUrl, "POST"); var authzUrl = "https://api.twitter.com/oauth/authorize?oauth_token=" + oauth["token"]; // here, should use a WebBrowser control. System.Diagnostics.Process.Start(authzUrl); // example only! // instruct the user to type in the PIN from that browser window var pin = "..."; var atUrl = "https://api.twitter.com/oauth/access_token"; oauth.AcquireAccessToken(atUrl, "POST", pin); // now, update twitter status using that access token var appUrl = "http://api.twitter.com/1/statuses/update.xml?status=Hello"; var authzHeader = oauth.GenerateAuthzHeader(appUrl, "POST"); var request = (HttpWebRequest)WebRequest.Create(appUrl); request.Method = "POST"; request.PreAuthenticate = true; request.AllowWriteStreamBuffering = true; request.Headers.Add("Authorization", authzHeader); using (var response = (HttpWebResponse)request.GetResponse()) { if (response.StatusCode != HttpStatusCode.OK) MessageBox.Show("There's been a problem trying to tweet:" + Environment.NewLine + response.StatusDescription); } 

OAuth 1.0a ist unter Deckeln ziemlich kompliziert, aber es muss nicht sein. Der OAuth.Manager behandelt die Generierung von ausgehenden OAuth-Anfragen und den Empfang und die Verarbeitung von OAuth-Inhalten in den Antworten. Wenn die Request_token-Anfrage Ihnen ein oauth_token gibt, muss Ihre App es nicht speichern. Der Oauth.Manager ist schlau genug, das automatisch zu machen. Wenn die access_token-Anforderung ein Zugriffstoken und einen geheimen Schlüssel zurückerhält, müssen Sie diese nicht explizit speichern. Der OAuth.Manager behandelt diesen Status für Sie.

Wenn Sie in nachfolgenden Läufen bereits das Zugriffstoken und das Geheimnis haben, können Sie den OAuth.Manager wie folgt instanziieren:

 var oauth = new OAuth.Manager(); oauth["consumer_key"] = CONSUMER_KEY; oauth["consumer_secret"] = CONSUMER_SECRET; oauth["token"] = your_stored_access_token; oauth["token_secret"] = your_stored_access_secret; 

… und dann Berechtigungsheader wie oben generieren.

 // now, update twitter status using that access token var appUrl = "http://api.twitter.com/1/statuses/update.xml?status=Hello"; var authzHeader = oauth.GenerateAuthzHeader(appUrl, "POST"); var request = (HttpWebRequest)WebRequest.Create(appUrl); request.Method = "POST"; request.PreAuthenticate = true; request.AllowWriteStreamBuffering = true; request.Headers.Add("Authorization", authzHeader); using (var response = (HttpWebResponse)request.GetResponse()) { if (response.StatusCode != HttpStatusCode.OK) MessageBox.Show("There's been a problem trying to tweet:" + Environment.NewLine + response.StatusDescription); } 

Sie können hier eine DLL mit der OAuth.Manager-class herunterladen. Es gibt auch eine Hilfedatei in diesem Download. Oder Sie können die Hilfedatei online anzeigen .

Sehen Sie sich ein Beispiel für ein Windows-Formular an, das diesen Manager hier verwendet .


Arbeitsbeispiel

Laden Sie ein funktionierendes Beispiel eines Befehlszeilentools herunter , das die hier beschriebene class und Technik verwendet: