具有.NET验证功能的OAuth

具有.NET验证功能的OAuth,.net,oauth,mendeley,.net,Oauth,Mendeley,我正在尝试创建一个基于.NET的客户端应用程序(在WPF中-尽管目前我只是作为一个控制台应用程序)来与支持OAuth的应用程序集成,特别是Mendeley(),它显然使用了三条腿的OAuth 这是我第一次使用OAuth,我在开始使用它时遇到了很多困难。我发现了几个.NETOAuth库或帮助程序,但它们似乎比我认为需要的更复杂。我想做的就是能够向Mendeley API发出REST请求并获得响应 到目前为止,我已经尝试: DotNetOpenAuth 第一个(DotNetOpenAuth)

我正在尝试创建一个基于.NET的客户端应用程序(在WPF中-尽管目前我只是作为一个控制台应用程序)来与支持OAuth的应用程序集成,特别是Mendeley(),它显然使用了三条腿的OAuth

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

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

  • DotNetOpenAuth
第一个(DotNetOpenAuth)似乎可以做我需要的事情,如果我花了好几个小时试着解决这个问题的话。第二个和第三个,据我所知,不支持门德雷发回的验证码——尽管我可能错了:)

我从Mendeley那里得到了一个消费者密钥和秘密,通过DotNetOpenAuth,我成功地启动了一个浏览器,其中包含Mendeley页面,为用户输入应用程序提供了验证码。然而,在这一点上,我迷路了,无法想出如何明智地将其提供给应用程序


我很愿意承认,我不知道从哪里开始(虽然这似乎有一个相当陡峭的学习曲线)-如果有人能给我指出正确的方向,我将不胜感激

我同意你的看法。可用于.NET应用程序的开放源码OAuth支持类很难理解,过于复杂(DotNetOpenAuth公开了多少方法?),设计很差(看看你提供的google链接中的OAuthBase.cs模块中有10个字符串参数的方法-根本没有状态管理),或者在其他方面不令人满意

没必要这么复杂

我不是OAuth方面的专家,但我已经生成了一个OAuth客户端管理器类,我成功地将其用于Twitter和TwitPic。它的使用相对简单。它是开源的,可在以下位置获得:

回顾一下,在OAuth 1.0a中,有一个特殊的名称,看起来像是一个“标准”,但据我所知,实现“OAuth 1.0a”的唯一服务是Twitter。我想这已经够标准了。好的,无论如何,在OAuth 1.0a中,它对桌面应用程序的工作方式如下:

  • 您,应用程序的开发者,注册应用程序并获得“消费者密钥”和“消费者机密”。在Arstechnica案中,确实有,但正如他们所说,这就是事实

  • 你的应用程序正在运行。它第一次运行时,需要让用户明确批准该应用程序向Twitter及其姐妹服务(如TwitPic)发出oauth认证的REST请求。要做到这一点,您必须通过一个审批流程,包括用户的明确批准。这种情况仅在应用程序第一次运行时发生。像这样:

    • 请求“请求令牌”。又名临时代币
    • 弹出一个网页,将该请求令牌作为查询参数传递。此网页向用户显示UI,询问“是否要授予此应用的访问权限?”
    • 用户登录到twitter网页,并授予或拒绝访问权限
    • 此时会出现响应html页面。如果用户已授予访问权限,将以48磅字体显示PIN
    • 用户现在需要将该pin剪切/粘贴到windows窗体框中,然后单击“下一步”或类似操作
    • 然后,桌面应用程序对“访问令牌”执行oauth身份验证请求。另一个休息请求
    • 桌面应用程序接收“访问令牌”和“访问密钥”
  • 在批准舞蹈之后,桌面应用程序只需使用特定于用户的“访问令牌”和“访问密钥”(以及特定于应用程序的“消费者密钥”和“消费者密钥”)代表用户向Twitter发出经过身份验证的请求。这些不会过期,尽管如果用户取消了应用程序的授权,或者Twitter出于某种原因取消了你的应用程序的授权,或者如果你丢失了访问令牌和/或密码,你需要再次进行审批


    如果您不聪明,UI流可以在某种程度上镜像多步骤OAuth消息流。有更好的办法

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

    像这样:


    如果已经对UI进行了排序,那么剩下的唯一挑战就是生成oauth签名的请求。这让很多人感到困惑,因为oauth的签名要求有点特殊。这就是简化的OAuth管理器类所做的

    请求令牌的示例代码:

    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参数的方法是通过基于字符串的索引器,类似于字典。AcquisiteRequestToken方法将oauth签名的请求发送到授予请求令牌(也称为临时令牌)的服务的URL。对于Twitter,此URL为“”。oauth规范说,您需要以某种方式(url编码并由符号连接)打包oauth参数集(令牌、令牌\u secret、nonce、时间戳、使用者\u密钥、版本和回调),并按照字典顺序对该结果生成签名,然后将这些相同的参数与签名一起打包,以不同的方式存储在新的oauth_签名参数中(用逗号连接)。OAuth管理器类会自动为您执行此操作。它会自动生成nonce、时间戳、版本和签名——你的应用不需要关心或意识到这些东西。只需设置oauth参数值并进行简单的方法调用。manager类发出请求并解析响应
    var url = SERVICE_SPECIFIC_AUTHORIZE_URL_STUB + oauth["token"];
    webBrowser1.Url = new Uri(url);
    
    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();
    
    webBrowser1.Visible = false; // all done with the web UI
    
    oauth.AcquireAccessToken(URL_ACCESS_TOKEN,
                             "POST",
                             pin);
    
    var authzHeader = oauth.GenerateAuthzHeader(url, "POST");
    
    var authzHeader = oauth.GenerateCredsHeader(URL_VERIFY_CREDS,
                                                "GET",
                                                AUTHENTICATION_REALM);
    
    // 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);
    }
    
    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);
    }