.NET'te Doğrulamalı OAuth


103

OAuth özellikli bir uygulamayla, özellikle Mendeley ( http: // dev .mendeley.com ), görünüşe göre 3 aşamalı OAuth kullanıyor.

Bu, OAuth'u ilk kullanışım ve kullanmaya başlamakta çok güçlük çekiyorum. Birkaç .NET OAuth kitaplığı veya yardımcı buldum, ancak ihtiyacım olduğunu düşündüğümden daha karmaşık görünüyorlar. Tek yapmak istediğim, Mendeley API'ye REST istekleri gönderebilmek ve yanıtları geri almak!

Şimdiye kadar denedim:

İlki (DotNetOpenAuth), nasıl çalıştığını bulmak için saatler ve saatler harcarsam ihtiyacım olanı yapabilir gibi görünüyor. İkinci ve üçüncü, söyleyebileceğim en iyi şekilde, Mendeley'in geri gönderdiği doğrulama kodlarını desteklemiyor - bu konuda yanılıyor da olabilirim :)

Mendeley'den bir tüketici anahtarım ve sırrım var ve DotNetOpenAuth ile, kullanıcının uygulamaya girmesi için bir doğrulama kodu sağlayan Mendeley sayfasıyla başlatılan bir tarayıcı almayı başardım. Ancak, bu noktada kayboldum ve bunu uygulamaya nasıl makul bir şekilde geri getireceğimi bilemedim.

Bununla nereden başlayacağıma dair hiçbir fikrim olmadığını itiraf etmeye çok istekliyim (oldukça dik bir öğrenme eğrisi var gibi görünse de) - eğer biri beni doğru yöne yönlendirebilirse çok sevinirim!

Yanıtlar:


183

Size katılıyorum. NET uygulamaları için mevcut olan açık kaynaklı OAuth destek sınıflarının anlaşılması zor, aşırı karmaşık (DotNetOpenAuth tarafından kaç yöntem açığa çıkarılıyor?), Kötü tasarlanmış (o google'daki OAuthBase.cs modülündeki 10 dize parametresine sahip yöntemlere bakın sağladığınız bağlantı - hiçbir eyalet yönetimi yoktur) veya başka şekilde tatmin edici değildir.

Bu kadar karmaşık olmasına gerek yok.

OAuth konusunda uzman değilim, ancak Twitter ve TwitPic ile başarılı bir şekilde kullandığım bir OAuth istemci tarafı yönetici sınıfı oluşturdum. Kullanımı nispeten basit. Açık kaynak kodludur ve şu adresten ulaşılabilir: Oauth.cs

İnceleme için, OAuth 1.0a'da ... biraz komik, özel bir ad var ve "standart" gibi görünüyor, ancak bildiğim kadarıyla "OAuth 1.0a" uygulayan tek hizmet Twitter'dır. Sanırım bu yeterince standart . tamam, her neyse, OAuth 1.0a'da masaüstü uygulamaları için çalışma şekli şöyledir:

  1. Siz, uygulamanın geliştiricisi, uygulamayı kaydettirin ve bir "tüketici anahtarı" ve "tüketici sırrı" alın. Arstechnica'da, bu modelin neden en iyisi olmadığına dair iyi yazılmış bir analiz var , ancak dedikleri gibi, ne olduğu .

  2. Uygulamanız çalışır. İlk çalıştırıldığında, kullanıcının Twitter'a ve onun kardeş hizmetlerine (TwitPic gibi) oauth-kimlik doğrulamalı REST istekleri yapması için uygulamaya açıkça onay vermesini sağlamalıdır. Bunu yapmak için, kullanıcının açık onayını içeren bir onay sürecinden geçmelisiniz. Bu, yalnızca uygulama ilk kez çalıştığında olur. Bunun gibi:

    • bir "istek belirteci" isteyin. Aka geçici belirteci.
    • bir web sayfası aç, bu istek belirtecini sorgu parametresi olarak ilet. Bu web sayfası, kullanıcıya "bu uygulamaya erişim izni vermek istiyor musunuz?" Diye soran kullanıcı arayüzünü sunar.
    • kullanıcı twitter web sayfasında oturum açar ve erişim izni verir veya reddeder.
    • yanıt html sayfası görünür. Kullanıcı erişim izni verdiyse, 48 pt yazı tipinde görüntülenen bir PIN vardır
    • kullanıcının artık bu iğneyi bir Windows form kutusuna yapıştırması ve "İleri" veya benzeri bir şeye tıklaması gerekir.
    • masaüstü uygulaması daha sonra bir "Erişim belirteci" için kimlik doğrulaması yapılmış bir istekte bulunur. Başka bir REST isteği.
    • masaüstü uygulaması "erişim jetonunu" ve "erişim sırrını" alır.

Onay dansının ardından masaüstü uygulaması, kullanıcı adına kimliği doğrulanmış isteklerde bulunmak için yalnızca kullanıcıya özel "erişim jetonu" ve "erişim sırrını" (uygulamaya özel "tüketici anahtarı" ve "tüketici sırrı" ile birlikte) kullanabilir Twitter'a. Kullanıcı uygulamanın yetkisini kaldırırsa veya Twitter herhangi bir nedenle uygulamanızın yetkisini kaldırırsa veya erişim jetonunuzu ve / veya sırrınızı kaybederseniz, onaylama işlemini tekrar yapmanız gerekir. .


Akıllı değilseniz, kullanıcı arayüzü akışı, çok adımlı OAuth mesaj akışını yansıtabilir. Daha iyi bir yol var.

Bir WebBrowser denetimi kullanın ve masaüstü uygulamasında yetkilendirme web sayfasını açın. Kullanıcı "İzin Ver" i tıkladığında, yanıt metnini bu Web Tarayıcısı kontrolünden alın, PIN'i otomatik olarak çıkarın ve ardından erişim belirteçlerini alın. 5 veya 6 HTTP isteği gönderiyorsunuz, ancak kullanıcının yalnızca tek bir İzin Ver / Reddet iletişim kutusu görmesi gerekiyor. Basit.

Bunun gibi:
alternatif metin


Kullanıcı arayüzünü sıraladıysanız, geriye kalan tek zorluk, oauth imzalı istekler üretmektir. Bu, birçok insanı tedirgin ediyor çünkü oauth imzalama gereksinimleri belirli bir tür. Basitleştirilmiş OAuth Manager sınıfının yaptığı budur.

Bir belirteç istemek için örnek kod:

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

İşte bu . Basit. Koddan da görebileceğiniz gibi, oauth parametrelere ulaşmanın yolu, dizge tabanlı bir indeksleyici, sözlük gibi bir şeydir. AcquireRequestToken yöntemi, istek belirteçleri, yani geçici belirteçler veren hizmetin URL'sine oauth imzalı bir istek gönderir. Twitter için bu URL " https://api.twitter.com/oauth/request_token " şeklindedir. Oauth spesifikasyonu, oauth parametreleri kümesini (token, token_secret, nonce, timestamp, tüketici_anahtar, sürüm ve geri arama), belirli bir şekilde (url ile kodlanmış ve ve işaretleriyle birleştirilen) ve bir sözlükbilimsel olarak paketlemeniz gerektiğini söylüyor. sıralı sıra, bu sonuç üzerinde bir imza oluşturur, ardından aynı parametreleri imzayla birlikte yeni oauth_signature parametresinde farklı bir şekilde (virgüllerle birleştirilir) paketler. OAuth yönetici sınıfı bunu sizin için otomatik olarak yapar. Otomatik olarak nonce'lar ve zaman damgaları, sürümler ve imzalar oluşturur - uygulamanızın bunları önemsemesi veya bunlardan haberdar olması gerekmez. Sadece oauth parametre değerlerini ayarlayın ve basit bir yöntem çağrısı yapın. yönetici sınıfı isteği gönderir ve yanıtı sizin için ayrıştırır.

Tamam, sonra ne? İstek jetonunu aldığınızda, kullanıcının açıkça onay vereceği web tarayıcısı kullanıcı arayüzünü açarsınız. Doğru yaparsanız, bunu gömülü bir tarayıcıya açarsınız. Twitter için, bunun URL'si oauth_token eklenmiş olarak " https://api.twitter.com/oauth/authorize?oauth_token= " şeklindedir. Bunu kodda şu şekilde yapın:

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

(Bunu harici bir tarayıcıda yapıyor olsaydın, kullanırdın System.Diagnostics.Process.Start(url).)

Url özelliğinin ayarlanması, WebBrowser denetiminin o sayfaya otomatik olarak gitmesine neden olur.

Kullanıcı "İzin Ver" düğmesine tıkladığında yeni bir sayfa yüklenecektir. Bu bir HTML formudur ve tam bir tarayıcıda olduğu gibi çalışır. Kodunuzda, WebBrowser denetiminin DocumentedCompleted olayı için bir işleyici kaydedin ve bu işleyicide pini tutun:

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

Bu biraz HTML ekran kazıma.

Pimi aldıktan sonra artık web tarayıcısına ihtiyacınız yok, yani:

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

... ve bunun için Dispose () işlevini de çağırmak isteyebilirsiniz.

Bir sonraki adım, bu pin ile birlikte başka bir HTTP mesajı göndererek erişim belirtecini almaktır. Bu, yukarıda tarif ettiğim oauth sıralama ve biçimlendirme ile oluşturulan başka bir imzalı oauth çağrısıdır. Ancak yine OAuth.Manager sınıfıyla bu gerçekten çok basit:

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

Twitter için bu URL " https://api.twitter.com/oauth/access_token " şeklindedir.

Artık erişim belirteçleriniz var ve bunları imzalı HTTP isteklerinde kullanabilirsiniz. Bunun gibi:

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

... urlkaynak uç noktası nerede . Kullanıcının durumunu güncellemek için " http://api.twitter.com/1/statuses/update.xml?status=Hello " olacaktır.

Ardından bu dizeyi Yetkilendirme adlı HTTP Üstbilgisine ayarlayın .

TwitPic gibi üçüncü taraf hizmetlerle etkileşim kurmak için, aşağıdaki gibi biraz farklı bir OAuth başlığı oluşturmanız gerekir :

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

Twitter için, doğrulama kredileri url'si ve bölgesi değerleri sırasıyla " https://api.twitter.com/1/account/verify_credentials.json " ve " http://api.twitter.com/ " şeklindedir.

... ve bu yetkilendirme dizesini X-Verify-Credentials-Authorization adlı bir HTTP başlığına yerleştirin . Ardından, gönderdiğiniz taleple birlikte bunu TwitPic gibi hizmetinize gönderin.

Bu kadar.

Hep birlikte, twitter durumunu güncelleme kodu şuna benzer bir şey olabilir:

// 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, örtü altında biraz karmaşıktır, ancak onu kullanmak zorunda değildir. OAuth.Manager, giden oauth isteklerinin oluşturulmasını ve yanıtlardaki oauth içeriğinin alınmasını ve işlenmesini yönetir. Request_token isteği size bir oauth_token verdiğinde, uygulamanızın bunu saklaması gerekmez. Oauth.Manager bunu otomatik olarak yapacak kadar akıllıdır. Aynı şekilde, access_token isteği bir erişim belirteci ve sırrı geri aldığında, bunları açıkça depolamanıza gerek yoktur. OAuth.Manager bu durumu sizin için halleder.

Sonraki çalıştırmalarda, erişim jetonuna ve sırrına zaten sahip olduğunuzda, OAuth.Manager'ı şu şekilde başlatabilirsiniz:

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;

... ve sonra yukarıdaki gibi yetkilendirme başlıkları oluşturun.

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

Sen indirebilirsiniz burada OAuth.Manager sınıfını içeren bir DLL . Bu indirmede bir yardım dosyası da var. Veya yardım dosyasını çevrimiçi olarak görüntüleyebilirsiniz .

Bu yöneticiyi kullanan bir Windows Formu örneğine buradan bakın .


ÇALIŞMA ÖRNEĞİ

Burada açıklanan sınıfı ve tekniği kullanan bir komut satırı aracının çalışan bir örneğini indirin :


Merhaba, cevabınız için çok teşekkürler! Aslında OAuth'tan geçtim (Mendeley'den vazgeçtim ve bir alternatifle gittim) - ama cevabınızı okudum ve çok mantıklı ve kapsamlı. İleride ihtiyaç duyabileceğim herhangi bir zaman için yazdığınız sınıfı da işaretledim! Tekrar çok teşekkürler.
John

2
Merhaba Cheeso, kodunuzu ve ayrıntılı açıklamanızı paylaştığınız için teşekkür ederiz. Harika ama basit bir çözüm sağladınız. Ancak, "oob" olmayan çözümleri desteklemek için GetSignatureBase yönteminizde küçük bir değişiklik yapmak isteyeceksiniz. "Oob" olmayanlar için, geri aramayı URL olarak kodlamanız gerekir, bu nedenle bu._params üzerinden yineleme yaparken böyle bir şey eklemek isteyeceksiniz: if (p1.Key == "geri arama") {p.Add ( "oauth_" + p1.Key, UrlEncode (p1.Value)); devam;}
Johnny Oshika

1
Bu, OAuth 2.0 için çalışmaz. Bu sınıf OAuth 1.0a içindir. OAuth2.0, çeşitli parametrelerin imzalanması ve sözlükbilimsel olarak sıralanması olmadığından, kullanımı önemli ölçüde daha kolaydır. Yani muhtemelen OAuth 2.0 yapmak için harici bir sınıfa ihtiyacınız yoktur, veya ... eğer harici bir sınıfa ihtiyacınız varsa, bundan çok daha basit olacaktır.
Cheeso


3
Tüm bağlantılar bozuk görünüyor. Burada bir kopya buldum: gist.github.com/DeskSupport/2951522#file-oauth-cs
John
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.