我正在尝试创建一个基于 .NET 的客户端应用程序(在 WPF 中 - 尽管目前我只是将其作为控制台应用程序)以与支持 OAuth 的应用程序集成,特别是 Mendeley (http://dev.mendeley.com),它显然使用 3 足 OAuth。
这是我第一次使用 OAuth,上手时遇到很多困难。我找到了几个 .NET OAuth 库或帮助程序,但它们似乎比我想象的更复杂。我想要做的就是能够向 Mendeley API 发出 REST 请求并获得响应!
到目前为止,我已经尝试过:
http://oauth.googlecode.com/svn/code/csharp/ 首先(DotNetOpenAuth)似乎如果我花了几个小时试图弄清楚如何做,它可能会做我需要的事情。据我所知,第二个和第三个不支持 Mendeley 发回的验证码——尽管我可能是错的:)
我从 Mendeley 获得了消费者密钥和秘密,并且通过 DotNetOpenAuth 我设法启动浏览器并使用 Mendeley 页面提供验证码供用户进入应用程序。然而,此时我迷失了方向,无法弄清楚如何明智地将其返回给应用程序。
我非常愿意承认我不知道从哪里开始(尽管似乎有一个相当陡峭的学习曲线) - 如果有人能指出我正确的方向,我将不胜感激!
I'm trying to create a .NET-based client app (in WPF - although for the time being I'm just doing it as a console app) to integrate with an OAuth-enabled application, specifically Mendeley (http://dev.mendeley.com), which apparently uses 3-legged OAuth.
This is my first time using OAuth, and I'm having a lot of difficulty getting started with it. I've found several .NET OAuth libraries or helpers, but they seem to be more complicated than I think I need. All I want to do is be able to issue REST requests to the Mendeley API and get responses back!
So far, I've tried:
The first (DotNetOpenAuth) seems like it could possibly do what I needed if I spent hours and hours trying to work out how. The second and third, as best I can tell, don't support the verification codes that Mendeley is sending back -- although I could be wrong about this :)
I've got a consumer key and secret from Mendeley, and with DotNetOpenAuth I managed to get a browser launched with the Mendeley page providing a verification code for the user to enter into the application. However, at this point I got lost and couldn't work out how to sensibly provide that back to the application.
I'm very willing to admit that I have no idea where to start with this (although it seems like there's quite a steep learning curve) - if anyone can point me in the right direction I'd appreciate it!
发布评论
评论(1)
我同意你的看法。可用于 .NET 应用程序的开源 OAuth 支持类很难理解、过于复杂(DotNetOpenAuth 公开了多少方法?)、设计不佳(查看来自 google 的 OAuthBase.cs 模块中具有 10 个字符串参数的方法)您提供的链接 - 根本没有状态管理),或者其他方面不令人满意。
不需要这么复杂。
我不是 OAuth 方面的专家,但我已经制作了一个 OAuth 客户端管理器类,我成功地将其与 Twitter 和 TwitPic 一起使用。使用起来相对简单。它是开源的,可在此处获取:Oauth.cs
供审核,在 OAuth 中1.0a ...有点有趣,有一个特殊的名称,它看起来像一个“标准”,但据我所知,唯一实现“OAuth 1.0a”的服务是 Twitter。我想这已经足够标准了。好吧,无论如何,在 OAuth 1.0a 中,桌面应用程序的工作方式是这样的:
您,应用程序的开发人员,注册应用程序并获取“消费者密钥”和“消费者秘密” ”。在 Arstechnica 上,有 对为什么这个模型不是最好的进行了很好的分析,但正如他们所说,它就是这样。
您的应用程序运行。第一次运行时,它需要让用户明确批准应用程序向 Twitter 及其姐妹服务(如 TwitPic)发出经过 oauth 身份验证的 REST 请求。为此,您必须经过批准流程,包括用户的明确批准。这种情况仅在应用程序第一次运行时发生。像这样:
在批准舞蹈之后,桌面应用程序可以仅使用用户特定的“访问令牌”和“访问秘密”(以及应用程序特定的“消费者密钥”和“消费者秘密”)代表用户执行经过身份验证的请求到推特。这些不会过期,但如果用户取消对应用程序的授权,或者 Twitter 出于某种原因取消对您的应用程序的授权,或者如果您丢失了访问令牌和/或秘密,则您需要再次进行批准舞蹈。
如果您不聪明,UI 流可以在某种程度上反映多步骤 OAuth 消息流。有一个更好的方法。
使用 WebBrowser 控件,并在桌面应用程序中打开授权网页。当用户单击“允许”时,从该 WebBrowser 控件中获取响应文本,自动提取 PIN,然后获取访问令牌。您发送 5 或 6 个 HTTP 请求,但用户只需要看到一个允许/拒绝对话框。简单的。
像这样:
如果您已经对 UI 进行了排序,那么剩下的唯一挑战就是生成 oauth 签名的请求。这让很多人感到困惑,因为认证签名要求有些特殊。这就是简化的 OAuth Manager 类的作用。
请求令牌的示例代码:
就是这样。简单的。从代码中可以看出,获取 oauth 参数的方法是通过基于字符串的索引器,类似于字典。 AcquireRequestToken 方法将 oauth 签名的请求发送到授予请求令牌(也称为临时令牌)的服务的 URL。对于 Twitter,此 URL 为“https://api.twitter.com/oauth/request_token” 。 oauth 规范表示,您需要以某种方式(url 编码并由 & 符号连接)并按字典顺序打包 oauth 参数集(token、token_secret、nonce、timestamp、consumer_key、version 和callback)。排序顺序,在该结果上生成签名,然后将这些相同的参数与签名一起打包,以不同的方式存储在新的 oauth_signature 参数中(用逗号连接)。 OAuth 管理器类会自动为您执行此操作。它会自动生成随机数、时间戳和版本和签名 - 您的应用程序无需关心或了解这些内容。只需设置 oauth 参数值并进行简单的方法调用即可。管理器类发出请求并为您解析响应。
好吧,然后呢?获得请求令牌后,您将弹出 Web 浏览器 UI,用户将在其中明确授予批准。如果你做得正确,你会在嵌入式浏览器中弹出它。对于 Twitter,其 URL 为“https://api.twitter.com/oauth/authorize ?oauth_token=" 并附加 oauth_token。在代码中执行此操作,如下所示:(
如果您在外部浏览器中执行此操作,则可以使用 System.Diagnostics.Process.Start(url)。)
设置 Url 属性会导致 WebBrowser 控件进行导航自动到该页面。
当用户单击“允许”按钮时,将加载新页面。它是一个 HTML 表单,其工作方式与在完整浏览器中相同。在您的代码中,为 WebBrowser 控件的 DocumentedCompleted 事件注册一个处理程序,然后在该处理程序中获取引脚:
这就是一些 HTML 屏幕抓取。
获取 pin 后,您不再需要 Web 浏览器,因此:
...您可能还想对其调用 Dispose()。
下一步是通过与该 pin 一起发送另一条 HTTP 消息来获取访问令牌。这是另一个签名的 oauth 调用,使用我上面描述的 oauth 排序和格式构建。但使用 OAuth.Manager 类,这又非常简单:
对于 Twitter,该 URL 是“https:// api.twitter.com/oauth/access_token”。
现在您拥有访问令牌,并且可以在签名的 HTTP 请求中使用它们。像这样:
...其中
url
是资源端点。要更新用户的状态,则为“http://api.twitter .com/1/statuses/update.xml?status=Hello”。然后将该字符串设置到名为 Authorization 的 HTTP 标头中。
要与第三方服务(例如 TwitPic)交互,您需要构造一个稍微不同的 OAuth 标头,如下所示:
对于 Twitter,验证信用 url 和领域的值为“https://api.twitter.com/1/account/verify_credentials.json" 和 "< a href="http://api.twitter.com/" rel="noreferrer">http://api.twitter.com/" 分别。
...并将该授权字符串放入名为X-Verify-Credentials-Authorization的HTTP标头中。然后将其连同您发送的任何请求一起发送到您的服务(例如 TwitPic)。
就是这样。
总而言之,更新 twitter 状态的代码可能是这样的:
OAuth 1.0a 在幕后有点复杂,但使用它并不需要如此。
OAuth.Manager 处理传出 oauth 请求的生成以及响应中 oauth 内容的接收和处理。当 Request_token 请求为您提供 oauth_token 时,您的应用程序不需要存储它。 Oauth.Manager 足够智能,可以自动执行此操作。同样,当 access_token 请求返回访问令牌和机密时,您不需要显式存储它们。 OAuth.Manager 为您处理该状态。
在后续运行中,当您已经拥有访问令牌和密钥时,您可以像这样实例化 OAuth.Manager:
...然后如上所述生成授权标头。
您可以在此处下载包含 OAuth.Manager 类的 DLL。该下载中还有一个帮助文件。或者您可以在线查看帮助文件。
请参阅此处使用此管理器的 Windows 窗体示例。
工作示例
下载命令行工具的工作示例使用此处描述的类和技术:
I agree with you. The open-source OAuth support classes available for .NET apps are hard to understand, overly complicated (how many methods are exposed by DotNetOpenAuth?), poorly designed (look at the methods with 10 string parameters in the OAuthBase.cs module from that google link you provided - there's no state management at all), or otherwise unsatisfactory.
It doesn't need to be this complicated.
I'm not an expert on OAuth, but I have produced an OAuth client-side manager class, that I use successfully with Twitter and TwitPic. It's relatively simple to use. It's open source and available here: Oauth.cs
For review, in OAuth 1.0a...kinda funny, there's a special name and it looks like a "standard" but as far as I know the only service that implements "OAuth 1.0a" is Twitter. I guess that's standard enough. ok, anyway in OAuth 1.0a, the way it works for desktop apps is this:
You, the developer of the app, register the app and get a "consumer key" and "consumer secret". On Arstechnica, there's a well written analysis of why this model isn't the best, but as they say, it is what it is.
Your app runs. The first time it runs, it needs to get the user to explicitly grant approval for the app to make oauth-authenticated REST requests to Twitter and its sister services (like TwitPic). To do this you must go through an approval process, involving explicit approval by the user. This happens only the first time the app runs. Like this:
After the approval dance, the desktop app can just use the user-specific "access token" and "access secret" (along with the app-specific "consumer key" and "consumer secret") to do authenticated requests on behalf of the user to Twitter. These don't expire, although if the user de-authorizes the app, or if Twitter for some reason de-authorizes your app, or if you lose your access token and/or secret, you'd need to do the approval dance again.
If you're not clever, the UI flow can sort of mirror the multi-step OAuth message flow. There is a better way.
Use a WebBrowser control, and open the authorize web page within the desktop app. When the user clicks "Allow", grab the response text from that WebBrowser control, extract the PIN automatically, then get the access tokens. You send 5 or 6 HTTP requests but the user needs to see only a single Allow/Deny dialog. Simple.
Like this:
If you've got the UI sorted, the only challenge that remains is to produce oauth-signed requests. This trips up lots of people because the oauth signing requirements are sort of particular. That's what the simplified OAuth Manager class does.
Example code to request a token:
THAT'S IT. Simple. As you can see from the code, the way to get to oauth parameters is via a string-based indexer, something like a dictionary. The AcquireRequestToken method sends an oauth-signed request to the URL of the service that grants request tokens, aka temporary tokens. For Twitter, this URL is "https://api.twitter.com/oauth/request_token". The oauth spec says you need to pack up the set of oauth parameters (token, token_secret, nonce, timestamp, consumer_key, version, and callback), in a certain way (url-encoded and joined by ampersands), and in a lexicographically-sorted order, generate a signature on that result, then pack up those same parameters along with the signature, stored in the new oauth_signature parameter, in a different way (joined by commas). The OAuth manager class does this for you automatically. It generates nonces and timestamps and versions and signatures automatically - your app doesn't need to care or be aware of that stuff. Just set the oauth parameter values and make a simple method call. the manager class sends out the request and parses the response for you.
Ok, then what? Once you get the request token, you pop the web browser UI in which the user will explicitly grant approval. If you do it right, you'll pop this in an embedded browser. For Twitter, the URL for this is "https://api.twitter.com/oauth/authorize?oauth_token=" with the oauth_token appended. Do this in code like so:
(If you were doing this in an external browser you'd use
System.Diagnostics.Process.Start(url)
.)Setting the Url property causes the WebBrowser control to navigate to that page automatically.
When the user clicks the "Allow" button a new page will be loaded. It's an HTML form and it works the same as in a full browser. In your code, register a handler for the DocumentedCompleted event of the WebBrowser control, and in that handler, grab the pin:
That's a bit of HTML screen scraping.
After grabbing the pin, you don't need the web browser any more, so:
...and you might want to call Dispose() on it as well.
The next step is getting the access token, by sending another HTTP message along with that pin. This is another signed oauth call, constructed with the oauth ordering and formatting I described above. But once again this is really simple with the OAuth.Manager class:
For Twitter, that URL is "https://api.twitter.com/oauth/access_token".
Now you have access tokens, and you can use them in signed HTTP requests. Like this:
...where
url
is the resource endpoint. To update the user's status, it would be "http://api.twitter.com/1/statuses/update.xml?status=Hello".Then set that string into the HTTP Header named Authorization.
To interact with third-party services, like TwitPic, you need to construct a slightly different OAuth header, like this:
For Twitter, the values for the verify creds url and realm are "https://api.twitter.com/1/account/verify_credentials.json", and "http://api.twitter.com/" respectively.
...and put that authorization string in an HTTP header called X-Verify-Credentials-Authorization. Then send that to your service, like TwitPic, along with whatever request you're sending.
That's it.
All together, the code to update twitter status might be something like this:
OAuth 1.0a is sort of complicated under the covers, but using it doesn't need to be.
The OAuth.Manager handles the generation of outgoing oauth requests, and the receiving and processing of oauth content in the responses. When the Request_token request gives you an oauth_token, your app doesn't need to store it. The Oauth.Manager is smart enough to do that automatically. Likewise when the access_token request gets back an access token and secret, you don't need to explicitly store those. The OAuth.Manager handles that state for you.
In subsequent runs, when you already have the access token and secret, you can instantiate the OAuth.Manager like this:
...and then generate authorization headers as above.
You can download a DLL containing the OAuth.Manager class here. There is also a helpfile in that download. Or you can view the helpfile online.
See an example of a Windows Form that uses this manager here.
WORKING EXAMPLE
Download a working example of a command-line tool that uses the class and technique described here: