我同意你的看法。对于.NET应用程序可用的开源OAuth支持类很难理解,过于复杂(DotNetOpenAuth公开了多少方法?),设计不佳(查看您提供的Google链接中的OAuthBase.cs模块中具有10个字符串参数的方法 - 根本没有状态管理),或者其他方面不尽人意。
这并不需要这么复杂。
我不是OAuth专家,但我已经编写了一个OAuth客户端管理器类,我已经成功地与Twitter和TwitPic一起使用。它相对简单易用。它是开源的,并在此处提供:Oauth.cs。
回顾一下,在OAuth 1.0a中...有点有趣,它有一个特殊的名称,看起来像一个“标准”,但据我所知,唯一实现“OAuth 1.0a”的服务是Twitter。 我想那就够标准了。 好吧,无论如何,在OAuth 1.0a中,它适用于桌面应用程序的方式是:
你作为应用程序的开发者,需要注册应用并获得"consumer key"和"consumer secret"。Arstechnica网站上有一篇关于为什么这种模式不是最好的分析,但正如他们所说,"它就是它"。
你的应用程序运行。第一次运行时,它需要让用户明确授权,以便应用程序可以通过oauth身份验证向Twitter及其姐妹服务(如TwitPic)进行REST请求。为此,您必须经过一个批准流程,包括用户的明确批准。这只在应用程序第一次运行时发生。流程如下:
- 请求一个"request token",也称为临时令牌。
- 弹出一个Web页面,将该请求令牌作为查询参数传递。该Web页面向用户呈现UI,询问"您是否要授权此应用程序访问?"
- 用户登录Twitter网页,并授予或拒绝访问权限。
- 响应的HTML页面出现。如果用户已授予访问权限,则会显示一个48号字体的PIN。
- 用户现在需要将那个PIN复制/粘贴到Windows表单框中,然后点击"下一步"或类似的按钮。
- 桌面应用程序然后执行oauth身份验证请求,以获取"Access token"。另一个REST请求。
- 桌面应用程序接收"access token"和"access secret"。
在认证通过后,桌面应用程序只需使用用户特定的"访问令牌"和"访问密钥"(以及应用程序特定的"消费者密钥"和"消费者密钥")代表用户向Twitter进行经过身份验证的请求。这些不会过期,但如果用户取消授权应用程序,或者Twitter出于某种原因取消了您的应用程序的授权,或者您丢失了访问令牌和/或秘密,您需要再次进行认证。
如果你不够聪明,UI流程会有点像多步骤OAuth消息流。 有更好的方式。
使用WebBrowser控件,在桌面应用程序中打开授权网页。 当用户点击“允许”时,从WebBrowser控件中获取响应文本,自动提取PIN,然后获取访问令牌。 您发送5或6个HTTP请求,但用户只需要看到一个Allow / Deny对话框。 简单。
就像这样:
如果你已经解决了UI问题,唯一需要解决的挑战就是生成OAuth签名请求。这会让很多人感到困惑,因为OAuth签名要求比较特殊。这就是简化的OAuth管理器类所做的事情。
请求令牌的示例代码:
var oauth = new OAuth.Manager();
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方法向授予临时令牌的服务的URL发送oauth签名请求。对于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。可以通过以下代码实现:
var url = SERVICE_SPECIFIC_AUTHORIZE_URL_STUB + oauth["token"];
webBrowser1.Url = new Uri(url);
(如果您在外部浏览器中执行此操作,则会使用System.Diagnostics.Process.Start(url)
。)
设置Url属性会导致WebBrowser控件自动导航到该页面。
当用户单击“允许”按钮时,将加载一个新页面。它是一个HTML表单,并且与完整浏览器中的操作方式相同。在您的代码中,为WebBrowser控件的DocumentCompleted事件注册处理程序,在该处理程序中获取PIN:
var divMarker = "<div id=\"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屏幕抓取相关的内容。
获取了PIN码后,您就不再需要Web浏览器了,因此:
webBrowser1.Visible = false
...并且您可能还想调用Dispose()。
下一步是通过发送另一个HTTP消息来获取访问令牌,并附带该pin。这是另一个签名的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"。
然后将该字符串设置为名为Authorization的HTTP标头。
要与TwitPic等第三方服务进行交互,您需要构建一个稍微不同的OAuth标头,如下所示:
var authzHeader = oauth.GenerateCredsHeader(URL_VERIFY_CREDS,
"GET",
AUTHENTICATION_REALM);
对于Twitter,验证凭证URL和领域的值分别为“
https://api.twitter.com/1/account/verify_credentials.json”和“
http://api.twitter.com/”。将该授权字符串放入名为
X-Verify-Credentials-Authorization的HTTP标头中,并将其与您发送的任何请求一起发送到您的服务,例如TwitPic。这就是全部。总体而言,更新Twitter状态的代码可能如下所示:
var rtUrl = "https://api.twitter.com/oauth/request_token";
var oauth = new OAuth.Manager();
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"];
System.Diagnostics.Process.Start(authzUrl);
var pin = "...";
var atUrl = "https://api.twitter.com/oauth/access_token";
oauth.AcquireAccessToken(atUrl, "POST", pin);
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请求,并接收和处理响应中的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;
...然后按照上述方法生成授权头。
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.Manager类的DLL文件a DLL containing the OAuth.Manager class here。该下载中还有一个帮助文件。或者,您可以在线查看帮助文件。
在此处here查看使用此管理器的Windows表单示例。
实际工作示例
下载一个实际工作示例,其中包含使用本文所述的类和技术的命令行工具: