OAuth met verificatie in .NET

Ik probeer een op .NET gebaseerde client-app te maken (in WPF – hoewel ik het voorlopig alleen doe als een console-app) om te integreren met een OAuth-toepassing, met name Mendeley (http://dev.mendeley.com), die blijkbaar driezijdige OAuth gebruikt.

Dit is de eerste keer dat ik OAuth gebruik en ik heb veel moeite om ermee aan de slag te gaan. Ik heb verschillende .NET OAuth-bibliotheken of helpers gevonden, maar ze lijken ingewikkelder dan ik denk dat ik nodig heb. Ik wil alleen maar REST-verzoeken kunnen sturen naar de Mendeley API en antwoorden terugkrijgen!

Tot nu toe heb ik het volgende geprobeerd:

De eerste (DotNetOpenAuth) lijkt mogelijk te doen wat ik nodig had als ik uren en uren zou besteden aan het uitzoeken hoe. De tweede en derde ondersteunen, voor zover ik weet, niet de verificatiecodes die Mendeley terugstuurt — hoewel ik me hierin kan vergissen 🙂

Ik heb een consumentensleutel en een geheim van Mendeley, en met DotNetOpenAuth is het me gelukt om een ​​browser te starten met de Mendeley-pagina die een verificatiecode geeft die de gebruiker kan invoeren in de applicatie. Op dit punt raakte ik echter verdwaald en kon ik er niet achter komen hoe ik dat op een verstandige manier kon teruggeven aan de applicatie.

Ik ben zeer bereid toe te geven dat ik geen idee heb waar ik hiermee moet beginnen (hoewel het lijkt alsof er een behoorlijk steile leercurve is) – als iemand me in de goede richting kan wijzen, zou ik dat op prijs stellen!

p>


Antwoord 1, autoriteit 100%

Ik ben het met je eens. De open-source OAuth-ondersteuningsklassen die beschikbaar zijn voor .NET-apps zijn moeilijk te begrijpen, te gecompliceerd (hoeveel methoden worden door DotNetOpenAuth weergegeven?), slecht ontworpen (kijk naar de methoden met 10 stringparameters in de OAuthBase.cs-module van die google link die je hebt gegeven – er is helemaal geen staatsbeheer), of anderszins onbevredigend.

Het hoeft niet zo ingewikkeld te zijn.

Ik ben geen expert op het gebied van OAuth, maar ik heb een OAuth client-side manager-klasse gemaakt, die ik met succes gebruik met Twitter en TwitPic. Het is relatief eenvoudig te gebruiken. Het is open source en hier beschikbaar: Oauth.cs

Ter beoordeling, in OAuth 1.0a… best wel grappig, er is een speciale naam en het ziet eruit als een “standaard”, maar voor zover ik weet is Twitter de enige service die “OAuth 1.0a” implementeert. Ik denk dat dat standaard genoegis. ok, hoe dan ook, in OAuth 1.0a werkt het voor desktop-appsals volgt:

  1. U, de ontwikkelaar van de app, registreert de app en krijgt een “consumentensleutel” en “consumentengeheim”. Op Arstechnica is er een goed geschreven analyse van waarom dit model niet het beste is, maar zoals ze zeggen, het is wat het is.

  2. Je app wordt uitgevoerd. De eerste keer dat het wordt uitgevoerd, moet het de gebruiker ertoe brengen expliciet toestemming te verlenen voor de app om oauth-geverifieerde REST-verzoeken te doen aan Twitter en zijn zusterservices (zoals TwitPic). Hiervoor moet u een goedkeuringsproces doorlopen, waarbij expliciete goedkeuring door de gebruiker is vereist. Dit gebeurt alleen de eerste keer dat de app wordt uitgevoerd. Zoals dit:

    • vraag een “verzoektoken” aan. Ofwel tijdelijke token.
    • pop een webpagina en geef dat verzoektoken door als een queryparameter. Deze webpagina geeft de gebruiker een gebruikersinterface met de vraag “wilt u toegang verlenen tot deze app?”
    • de gebruiker logt in op de twitter-webpagina en verleent of weigert toegang.
    • de respons-html-pagina verschijnt. Als de gebruiker toegang heeft verleend, wordt er een pincode weergegeven in een lettertype van 48 punten
    • de gebruiker moet die pin nu knippen/plakken in een venster in een formuliervenster en op “Volgende” of iets dergelijks klikken.
    • de desktop-app doet dan een oauth-geverifieerd verzoek om een ​​”Toegangstoken”. Nog een REST-verzoek.
    • de desktop-app ontvangt het “toegangstoken” en “toegangsgeheim”.

Na de goedkeuringsdans kan de desktop-app gewoon het gebruikersspecifieke ‘toegangstoken’ en ‘toegangsgeheim’ gebruiken (samen met de app-specifieke ‘consumentensleutel’ en ‘consumentengeheim’) om namens geverifieerde verzoeken te doen van de gebruiker naar Twitter. Deze verlopen niet, maar als de gebruiker de autorisatie van de app intrekt, of als Twitter om de een of andere reden de autorisatie van uw app intrekt, of als u uw toegangstoken en/of geheim verliest, moet u de goedkeuringsdans opnieuw doen .


Als je niet slim bent, kan de UI-stroom de OAuth-berichtenstroom met meerdere stappen weerspiegelen. Er is een betere manier.

Gebruik een WebBrowser-besturingselement en open de autorisatie-webpagina in de desktop-app. Wanneer de gebruiker op “Toestaan” klikt, pak dan de antwoordtekst van dat WebBrowser-besturingselement, extraheer de pincode automatisch en verkrijg vervolgens de toegangstokens. U verzendt 5 of 6 HTTP-verzoeken, maar de gebruiker hoeft maar één dialoogvenster Toestaan/Weigeren te zien. Eenvoudig.

Zoals dit:
alt-tekst


Als je de gebruikersinterface op orde hebt, is de enige uitdaging die overblijft het produceren van OAuth-ondertekende verzoeken. Dit brengt veel mensen in de war omdat de vereisten voor het ondertekenen van de eed nogal bijzonder zijn. Dat is wat de vereenvoudigde OAuth Manager-klasse doet.

Voorbeeldcode om een ​​token aan te vragen:

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");

DAT IS HET. Gemakkelijk. Zoals je aan de code kunt zien, is de manier om bij OAuth-parameters te komen via een op tekenreeksen gebaseerde indexer, zoiets als een woordenboek. De methode AcquireRequestToken verzendt een OAuth-ondertekende aanvraag naar de URL van de service die aanvraagtokens toekent, oftewel tijdelijke tokens. Voor Twitter is deze URL “https://api.twitter.com/oauth/request_token” . De oauth-specificatie zegt dat je de set oauth-parameters (token, token_secret, nonce, timestamp, consumer_key, version en callback) op een bepaalde manier moet inpakken (url-gecodeerd en samengevoegd door ampersands), en in een lexicografisch- sorteervolgorde, genereer een handtekening op dat resultaat en verpak diezelfde parameters samen met de handtekening, opgeslagen in de nieuwe parameter oauth_signature, op een andere manier (samengevoegd door komma’s). De OAuth-managerklasse doet dit automatisch voor u.Het genereert automatisch nonces en tijdstempels en versies en handtekeningen– uw app hoeft zich daar niets van aan te trekken of zich daarvan bewust te zijn. Stel gewoon de OAuth-parameterwaarden in en voer een eenvoudige methodeaanroep uit. de managerklasse verzendt het verzoek en parseert het antwoord voor u.

Ok, wat dan? Zodra u de aanvraagtoken hebt ontvangen, opent u de gebruikersinterface van de webbrowser waarin de gebruiker expliciet goedkeuring verleent. Als je het goed doet, zal je dit in een ingesloten browser plaatsen. Voor Twitter is de URL hiervoor “https://api.twitter.com/oauth/authorize ?oauth_token=” met de oauth_token toegevoegd. Doe dit in code als volgt:

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

(Als u dit in een externe browser zou doen, zou u System.Diagnostics.Process.Start(url)gebruiken.)

Als u de eigenschap URL instelt, gaat het besturingselement WebBrowser automatisch naar die pagina.

Als de gebruiker op de knop “Toestaan” klikt, wordt een nieuwe pagina geladen. Het is een HTML-formulier en het werkt hetzelfde als in een volledige browser. Registreer in uw code een handler voor de DocumentedCompleted-gebeurtenis van het WebBrowser-besturingselement en pak in die handler de pin:

var divMarker = "<div id=\"oauth_pin\">"; // 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();

Dat is een beetje HTML-schermschrapen.

Nadat je de pin hebt gepakt, heb je de webbrowser niet meer nodig, dus:

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

…en misschien wilt u er ook Dispose() op aanroepen.

De volgende stap is het verkrijgen van het toegangstoken door samen met die pin een ander HTTP-bericht te verzenden. Dit is weer een ondertekende OAuth-aanroep, geconstrueerd met de OAuth-bestelling en -opmaak die ik hierboven heb beschreven. Maar nogmaals, dit is heel eenvoudig met de OAuth.Manager-klasse:

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

Voor Twitter is die URL “https://api.twitter.com/oauth/access_token“.

Je hebt nu toegangstokens en je kunt ze gebruiken in ondertekende HTTP-verzoeken. Zoals dit:

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

…waar urlhet resource-eindpunt is. Om de status van de gebruiker bij te werken, is dit “http://api.twitter .com/1/statuses/update.xml?status=Hallo“.

Stel die string vervolgens in de HTTP-header in met de naam Autorisatie.

Als u wilt communiceren met services van derden, zoals TwitPic, moet u een iets andereOAuth-header maken, zoals deze:

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

Voor Twitter zijn de waarden voor de url en realm van de verificatiegegevens “https:// api.twitter.com/1/account/verify_credentials.json“, en “http://api.twitter .com/” respectievelijk.

…en plaats dieautorisatiereeks in een HTTP-header met de naam X-Verify-Credentials-Authorization. Stuur dat dan naar je service, zoals TwitPic, samen met het verzoek dat je verzendt.

Dat is het.

Alles bij elkaar zou de code om de Twitter-status bij te werken er ongeveer zo uit kunnen zien:

// 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 is een beetje ingewikkeld onder de dekens, maar het gebruik ervan hoeft niet zo te zijn.
De OAuth.Manager zorgt voor het genereren van uitgaande OAuth-verzoeken en het ontvangen en verwerken van OAuth-inhoud in de reacties. Wanneer de Request_token-aanvraag u een oauth_token geeft, hoeft uw app deze niet op te slaan. De Oauth.Manager is slim genoeg om dat automatisch te doen. Evenzo, wanneer het access_token-verzoek een toegangstoken en geheim terugkrijgt, hoeft u deze niet expliciet op te slaan. De OAuth.Manager handelt die status voor u af.

In volgende uitvoeringen, wanneer u al over het toegangstoken en geheim beschikt, kunt u de OAuth.Manager als volgt instantiëren:

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;

…en genereer vervolgens autorisatieheaders zoals hierboven.

// 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);
}

Je kunt een DLL met de OAuth.Manager-klasse hier downloaden. Er is ook een helpbestand in die download. Of u kunt het helpbestand online bekijken.

Bekijk hiereen voorbeeld van een Windows-formulier dat deze manager gebruikt .


WERKVOORBEELD

Download een werkend voorbeeldvan een opdrachtregelprogramma dat de klasse en techniek gebruikt hier beschreven:

Other episodes