OAuth с проверкой в ​​.NET - PullRequest
       21

OAuth с проверкой в ​​.NET

97 голосов
/ 23 октября 2010

Я пытаюсь создать клиентское приложение на основе .NET (в WPF - хотя пока я просто делаю это как консольное приложение) для интеграции с приложением с поддержкой OAuth, в частности, с Mendeley (http://dev.mendeley.com),, который, по-видимому, использует 3-х сторонний OAuth.

Это мой первый раз, когда я использую OAuth, и у меня возникают большие трудности с его началом. Я нашел несколько библиотек .NET OAuth или помощников, но они кажутся более сложными, чем мне кажется. Все, что я хочу сделать, это иметь возможность отправлять REST-запросы в API Mendeley и получать ответы обратно!

Пока что пробовал:

Первый (DotNetOpenAuth), похоже, мог бы сделать то, что мне нужно, если бы я потратил часы и часы, пытаясь понять, как. Второй и третий, насколько я могу судить, не поддерживают коды подтверждения, которые Менделей отправляет обратно - хотя я могу ошибаться по этому поводу:)

Я получил ключ и секрет потребителя от Mendeley, и с помощью DotNetOpenAuth мне удалось запустить браузер со страницей Mendeley, предоставляющей код подтверждения для входа пользователя в приложение. Однако в этот момент я заблудился и не мог понять, как разумно передать это обратно в приложение.

Я очень хочу признать, что понятия не имею, с чего начать (хотя кажется, что есть довольно крутая кривая обучения) - если кто-то может указать мне правильное направление, я буду признателен!

1 Ответ

171 голосов
/ 16 декабря 2010

Я согласен с вами.Классы поддержки OAuth с открытым исходным кодом, доступные для приложений .NET, сложны для понимания, слишком сложны (сколько методов доступно для DotNetOpenAuth?), Плохо разработаны (посмотрите на методы с 10 строковыми параметрами в модуле OAuthBase.cs из этого Googleссылка, которую вы предоставили - нет никакого государственного управления вообще), или в противном случае неудовлетворительно.

Это не должно быть так сложно.

Я не эксперт по OAuth, но я разработал класс менеджера на стороне клиента OAuth, который я успешно использую с Twitter и TwitPic.Это относительно просто в использовании.Он с открытым исходным кодом и доступен здесь: Oauth.cs

Для обзора, в OAuth 1.0a ... довольно забавно, есть специальное имя, и оно выглядит как "стандартное", но наскольконасколько я знаю, единственным сервисом, реализующим OAuth 1.0a, является Twitter.Я думаю, это стандартно достаточно .Хорошо, в любом случае в OAuth 1.0a способ работы для настольных приложений таков:

  1. Вы, разработчик приложения, регистрируете приложение и получаете«Ключ потребителя» и «Секрет потребителя».На Arstechnica есть хорошо написанный анализ того, почему эта модель не самая лучшая , но, как говорится, это то, чем она является .

  2. Ваше приложение работает.При первом запуске необходимо, чтобы пользователь явно разрешил приложению отправлять запросы REST с аутентификацией oauth в Twitter и его родственные службы (например, TwitPic).Для этого вы должны пройти процедуру одобрения, включая явное одобрение пользователя.Это происходит только при первом запуске приложения.Например:

    • запросить «маркер запроса».Ака временный токен.
    • открывает веб-страницу, передавая этот маркер запроса в качестве параметра запроса.Эта веб-страница представляет пользовательский интерфейс с вопросом "хотите ли вы предоставить доступ к этому приложению?"
    • пользователь входит в систему на веб-странице Twitter и предоставляет или запрещает доступ.
    • Появляется html-страница ответа.Если пользователь предоставил доступ, есть PIN-код, отображаемый шрифтом 48-pt
    • , теперь пользователю нужно вырезать / вставить этот пин-код в поле формы Windows и нажать «Далее» или что-то подобное.
    • настольное приложение затем выполняет oauth-аутентифицированный запрос на «токен доступа».Еще один запрос REST.
    • настольное приложение получает «токен доступа» и «секрет доступа».

После танца одобрения настольное приложение может просто использовать пользовательский «токен доступа» и «секрет доступа» (наряду с «ключом потребителя» приложения)и «секрет пользователя») для выполнения аутентифицированных запросов от имени пользователя в Twitter.Они не истекают, хотя, если пользователь отменяет авторизацию приложения, или если Twitter по какой-то причине отменяет авторизацию вашего приложения, или если вы потеряете свой токен доступа и / или секрет, вам нужно будет выполнить танец одобрения снова,


Если вы не умны, поток пользовательского интерфейса может как бы отражать многошаговый поток сообщений OAuth.Существует лучший способ.

Используйте элемент управления WebBrowser и откройте веб-страницу авторизации в настольном приложении.Когда пользователь нажимает «Разрешить», возьмите текст ответа из этого элемента управления WebBrowser, автоматически извлеките ПИН-код и получите токены доступа.Вы отправляете 5 или 6 HTTP-запросов, но пользователь должен видеть только один диалог Разрешить / Запретить.Простой.

Пример:
alt text


Если у вас отсортирован пользовательский интерфейс, единственная оставшаяся проблема - это создание запросов с подписью oauth.Это сбивает с толку многих людей, потому что требования подписи oauth являются специфическими.Это то, что делает упрощенный класс OAuth Manager.

Пример кода для запроса токена:

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

ЭТО ЭТО .Просто.Как видно из кода, путь к параметрам oauth можно получить через индексатор на основе строк, что-то вроде словаря.Метод AcquireRequestToken отправляет запрос с подписью oauth на URL-адрес службы, которая предоставляет маркеры запросов, или временные токены.Для Twitter этот URL-адрес "https://api.twitter.com/oauth/request_token". Спецификация oauth говорит, что вам нужно определенным образом упаковать набор параметров oauth (токен, token_secret, nonce, отметка времени, customer_key, version и callback)(закодированы и объединены с помощью амперсандов) и в лексикографически отсортированном порядке сгенерируйте подпись для этого результата, затем упакуйте те же параметры вместе с подписью, сохраненной в новом параметре oauth_signature, другим способом (соединенным запятыми). Класс менеджера OAuth делает это для вас автоматически. Он автоматически генерирует одноразовые и временные метки, а также версии и подписи - вашему приложению не нужно заботиться или знать об этом.установите значения параметров oauth и выполните простой вызов метода. Класс менеджера отправляет запрос и анализирует ответ для вас.

Хорошо, тогда что? Как только вы получите токен запроса, вы откроете пользовательский интерфейс веб-браузера.в котором пользователь явно предоставит одобрение. Если вы все сделаете правильно, вы увидите это ввстроенный браузерДля Twitter, URL для этого: "https://api.twitter.com/oauth/authorize?oauth_token=" с добавленным oauth_token. Сделайте это в коде так:

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

(Если бы вы делали это во внешнем браузере, вы бы использовалиSystem.Diagnostics.Process.Start(url).)

Установка свойства Url заставляет элемент управления WebBrowser автоматически переходить на эту страницу.

Когда пользователь нажимает кнопку «Разрешить», будет загружена новая страница.HTML-форма, и она работает так же, как в полном браузере. В вашем коде зарегистрируйте обработчик для события DocumentedCompleted элемента управления WebBrowser и в этом обработчике возьмите булавку:

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

Это немногоочистки экрана HTML.

После захвата булавки вам больше не нужен веб-браузер, поэтому:

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

... и вы можете вызвать Dispose ()на этом тоже.

Следующим шагом является получение токена доступа путем отправки другого HTTP-сообщения вместе с этим выводом. Это еще один подписанный вызов oauth, созданный с использованием порядка и форматирования oauth, который я описал выше.Еще раз, это действительно просто с классом OAuth.Manager:

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

Для Twitter этот URL-адрес "https://api.twitter.com/oauth/access_token".

Теперь у вас есть токены доступа, и вы можетеиспользуйте их в подписанных HTTP-запросах.Например:

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

... где url - конечная точка ресурса.Чтобы обновить статус пользователя, это будет "http://api.twitter.com/1/statuses/update.xml?status=Hello".

Затем установите эту строку в заголовок HTTP с именем Авторизация .

Для взаимодействия с третьимсторонним сервисам, таким как TwitPic, вам нужно создать немного другой заголовок OAuth, например:

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

Для Twitter значения URL-адресов и областей проверки кредитов "" 1111*https://api.twitter.com/1/account/verify_credentials.json", и "http://api.twitter.com/" соответственно.

... и поместите эту строку авторизации в заголовок HTTP с именем X-Verify-Credentials-Authorization . Затем отправьте это в ваш сервис, например, TwitPic, вместе с любым запросом, который вы отправляете.

Вот и все.

Все вместе, код для обновления статуса Twitter может быть примерно такимэто:

// 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 довольно сложен под прикрытием, но использовать его не обязательно. OAuth.Manager обрабатывает генерацию исходящих запросов oauth, а также получение и обработкусодержание в ответах.Когда запрос Request_token дает вам oauth_token, вашему приложению не нужно его хранить.Oauth.Manager достаточно умен, чтобы делать это автоматически.Аналогично, когда запрос access_token возвращает токен доступа и секрет, вам не нужно явно хранить их.OAuth.Manager обрабатывает это состояние для вас.

В последующих запусках, когда у вас уже есть токен доступа и секрет, вы можете создать экземпляр OAuth.Manager следующим образом:

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;

... и затем сгенерируйте заголовки авторизации, как указано выше.

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

Вы можете скачать DLL, содержащую класс OAuth.Manager, здесь . В этой загрузке также есть файл справки. Или вы можете просмотреть справочный файл онлайн .

См. Пример формы Windows, в которой используется этот менеджер здесь .


ПРИМЕР РАБОТЫ

Загрузите рабочий пример инструмента командной строки, который использует класс и технику, описанную здесь:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...