.net - .NET中具有验证功能的OAuth

标签 .net oauth mendeley

我正在尝试创建一个基于.NET的客户端应用程序(在WPF中-尽管目前我只是作为控制台应用程序进行集成),以与支持OAuth的应用程序(特别是Mendeley(http://dev.mendeley.com))集成,显然使用了三足式OAuth。

这是我第一次使用OAuth,在开始使用它时遇到了很多困难。我已经找到了几个.NET OAuth库或帮助程序,但是它们似乎比我想的要复杂。我要做的就是能够向Mendeley API发出REST请求并获得响应!

到目前为止,我已经尝试过:


DotNetOpenAuth
http://github.com/bittercoder/DevDefined.OAuth
http://oauth.googlecode.com/svn/code/csharp/


第一个(DotNetOpenAuth)似乎可以完成我需要的工作,如果我花了数小时来尝试如何做。据我所知,第二和第三个不支持Mendeley发送回的验证码-尽管我对此可能是错的:)

我从Mendeley获得了一个消费者密钥和秘密,并且使用DotNetOpenAuth设法启动了一个带有Mendeley页面的浏览器,该页面提供了供用户输入应用程序的验证码。但是,此时我迷路了,无法解决如何明智地将其提供回应用程序的问题。

我非常愿意承认我不知道从哪里开始(尽管似乎学习曲线很陡峭)-如果有人可以指出正确的方向,我将不胜感激!

最佳答案

我同意你的看法。 .NET应用程序可用的开源OAuth支持类很难理解,过于复杂(DotNetOpenAuth公开了多少种方法?),设计欠佳(请参阅来自Google的OAuthBase.cs模块中具有10个字符串参数的方法)您提供的链接-根本没有状态管理),否则就不能令人满意。

不需要这么复杂。

我不是OAuth专家,但是我制作了OAuth客户端管理器类,该类已成功用于Twitter和TwitPic。使用起来比较简单。它是开源的,可以在这里找到:Oauth.cs

为了进行审查,在OAuth 1.0a ...有点有趣的情况下,有一个特殊的名称,它看起来像是“标准”,但据我所知,唯一实现“ OAuth 1.0a”的服务是Twitter。我想这已经足够标准了。好的,无论如何,在OAuth 1.0a中,它对桌面应用的工作方式是这样的:


您(该应用程序的开发者)注册该应用程序并获得“消费者密钥”和“消费者秘密”。在Arstechnica上有a well written analysis of why this model isn't the best,但是正如他们所说的那样。
您的应用运行。首次运行时,它需要使用户明确批准该应用程序,以便向Twitter及其姊妹服务(例如TwitPic)发出经oauth认证的REST请求。为此,您必须经过批准过程,涉及用户的明确批准。这仅在应用程序首次运行时发生。像这样:


请求一个“请求令牌”。又名临时令牌。
弹出网页,将该请求令牌作为查询参数传递。该网页向用户显示UI,询问“您是否要授予对此应用程序的访问权限?”
用户登录到Twitter网页,并授予或拒绝访问。
出现响应html页面。如果用户已授予访问权限,则会以48点字体显示PIN
用户现在需要将图钉剪切/粘贴到Windows窗体框中,然后单击“下一步”或类似内容。
然后,桌面应用程序会对“访问令牌”进行经过oauth身份验证的请求。另一个REST请求。
桌面应用会收到“访问令牌”和“访问密码”。



在批准舞蹈之后,桌面应用程序可以仅使用用户特定的“访问令牌”和“访问秘密”(以及应用程序特定的“消费者密钥”和“消费者秘密”)代表用户执行经过身份验证的请求到Twitter。这些不会过期,尽管如果用户取消了该应用的授权,或者如果Twitter由于某种原因取消了您的应用的授权,或者如果您丢失了访问令牌和/或机密,则需要再次进行批准操作。



如果您不聪明,则UI流程可以类似于多步OAuth消息流程的镜像。有个更好的方法。

使用WebBrowser控件,然后在桌面应用程序中打开授权网页。当用户单击“允许”时,从该WebBrowser控件中获取响应文本,自动提取PIN,然后获取访问令牌。您发送5或6个HTTP请求,但用户只需要看到一个“允许/拒绝”对话框。简单。

像这样:




如果您已经对UI进行了排序,那么剩下的唯一挑战就是生成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,该URL授予请求令牌(也称为临时令牌)。对于Twitter,此URL为“ https://api.twitter.com/oauth/request_token”。 oauth规范表示,您需要以某种方式(URL编码并由&符组合)并以字典上的方式打包oauth参数集(令牌,token_secret,随机数,时间戳,consumer_key,版本和回调)。排序后,在该结果上生成签名,然后将这些相同的参数与签名一起打包,并以另一种方式(存储在新的oauth_signature参数中)(以逗号分隔)。 OAuth管理器类会自动为您执行此操作。它会自动生成随机数和时间戳,版本和签名-您的应用无需关心或注意这些内容。只需设置oauth参数值并进行简单的方法调用即可。 manager类发出请求并为您解析响应。

好那怎么了获取请求令牌后,将弹出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控件的DocumentedCompleted事件注册一个处理程序,然后在该处理程序中抓图钉:

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”。

然后将该字符串设置到名为Authorization的HTTP标头中。

要与第三方服务(例如TwitPic)进行交互,您需要构建稍微不同的OAuth标头,如下所示:

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


对于Twitter,验证凭据url和realm的值分别为“ https://api.twitter.com/1/account/verify_credentials.json”和“ http://api.twitter.com/”。

...并将该授权字符串放在称为X-Verify-Credentials-Authorization的HTTP标头中。然后将其连同您发送的任何请求一起发送到您的服务,例如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请求的生成,以及响应中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);
}


您可以下载a DLL containing the OAuth.Manager class here。该下载中也有一个帮助文件。或者您可以view the helpfile online

请参阅使用此管理器here的Windows窗体的示例。



工作实例

使用此处描述的类和技术的命令行工具的Download a working example

关于.net - .NET中具有验证功能的OAuth,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12925488/

相关文章:

Mendeley Oauth2 API : Has full-text search been dropped?

Python Mendeley SDK API 在身份验证中返回错误

linux - 在 Mac 和 Linux 中将 Mendeley 库与 Dropbox 同步

c# - 如何使用 LINQ to SQL/ADO.NET 获取执行计划

c# - 使用 C# API 进行 iOS 开发

java - DefaultHttpClient 引发由 : java. lang.ClassNotFoundException : org. slf4j.LoggerFactory 引起

python - 如果用户有多个电子邮件地址,我是否需要存储多个 oauth token ?

c# - 在 .NET 中是否有用于长时间运行线程的线程调度程序?

c# - 仅返回列表 C# 中包含的值

iphone - 使用 Facebook iPhone SDK 时如何刷新 oauth token