mendeley identityserver4中文 - 在.NET中使用验证的OAuth




identityserver4教程 oauth2 (2)

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

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

到目前为止,我试过了:

第一个(DotNetOpenAuth)似乎可以做我需要的东西,如果我花费数小时的时间来设法解决问题。 第二和第三,尽我所知,不支持门德利送回的验证码 - 虽然我可能错了:)

我有一个来自Mendeley的消费者密钥和秘密,通过DotNetOpenAuth,我设法使用Mendeley页面启动浏览器,为用户提供验证码,以便输入到应用程序中。 然而,在这一点上,我迷失了方向,无法理解如何合理地将其提供给应用程序。

我非常愿意承认,我不知道从哪里开始(虽然看起来有相当陡峭的学习曲线) - 如果任何人都可以指出我正确的方向,我会很感激!


Answers

我赞同你。 可用于.NET应用程序的开源OAuth支持类很难理解,过于复杂(DotNetOpenAuth公开了多少种方法?),设计不佳(查看来自该谷歌的OAuthBase.cs模块中包含10个字符串参数的方法你提供的链接 - 根本没有国家管理),否则不令人满意。

它不需要这么复杂。

我不是OAuth的专家,但我已经制作了一个OAuth客户端管理员课程,我成功地使用了Twitter和TwitPic。 它使用起来相对简单。 它是开源的,可以在这里找到: Oauth.cs

对于OAuth 1.0a来说,有趣的是,有一个特殊的名字,它看起来像一个“标准”,但据我所知,实现“OAuth 1.0a”的唯一服务是Twitter。 我想这足够标准。 好的,无论如何,在OAuth 1.0a中,它适用于桌面应用程序的方式如下:

  1. 您是该应用程序的开发人员,注册该应用程序并获得“消费者密钥”和“消费者机密”。 在Arstechnica,有一篇关于为什么这个模型不是最好的分析的书面分析 ,但正如他们所说的那样, 它就是这样

  2. 您的应用运行。 它首次运行时,需要让用户明确授予应用程序对Twitter和其姊妹服务(如TwitPic)进行oauth认证的REST请求。 要做到这一点,您必须通过审批流程,并由用户明确批准。 这只会在应用第一次运行时发生。 喜欢这个:

    • 请求“请求令牌”。 又名临时令牌。
    • 弹出一个网页,将该请求标记作为查询参数传递。 这个网页向用户展示用户界面,询问“你想授予访问这个应用程序的权限吗?”
    • 用户登录到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,也就是临时令牌。 对于Twitter,这个URL是“ https://api.twitter.com/oauth/request_token ”。 oauth规范说,您需要以某种方式(url编码并通过&符号连接)打包一组oauth参数(token,token_secret,nonce,timestamp,consumer_key,版本和回调),并以字典形式 - 按照排序顺序生成该结果的签名,然后将这些相同的参数与存储在新的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控件的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屏幕抓取。

抓住引脚后,您不再需要Web浏览器,因此:

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

要与TwitPic等第三方服务交互,您需要构建一个稍微不同的 OAuth标头,如下所示:

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

对于Twitter,验证信用网址和领域的值分别为“ 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);
}

您可以在此下载包含OAuth.Manager类的DLL 。 该下载中还有一个帮助文件。 或者你可以在线查看帮助文件

查看here使用此管理器的Windows窗体的示例。

工作的例子

下载一个使用此处描述的类和技术的命令行工具的工作示例


通常的解释是,当您使用JavaScript客户端时,隐式授权更容易实现。 但我认为这是看错的方法。 如果您使用通过XMLHttpRequest直接请求受保护资源的JavaScript客户端,隐式授权是您唯一的选择,尽管它不太安全。

授权代码授权提供了额外的安全性,但只有当您有Web服务器请求受保护的资源时才能使用。 由于Web服务器可以存储访问令牌,因此访问令牌暴露给Internet的风险较小,您可以发出持续很长时间的令牌。 由于Web服务器是可信的,因此可以给它一个“刷新令牌”,以便在旧服务器到期时可以获得新的访问令牌。

但是 - 这是一个很容易忽略的问题 - 只有当Web服务器受到使用用户身份验证(登录)建立的会话的保护时,授权代码流的安全性才有效。 如果没有会话,不受信任的用户可以使用client_id向Web服务器发出请求,并且与用户拥有访问令牌的情况相同。 添加会话意味着只有经过身份验证的用户才能访问受保护的资源。 client_id只是JS webapp的“身份”,而不是所述webapp的认证。

这也意味着您可以在OAuth令牌过期之前结束会话。 没有标准的方法来使访问令牌失效。 但是如果你的会话过期了,访问令牌就没用了,因为没有人知道它,但是Web服务器。 如果不受信任的用户获得对会话密钥的访问权限,则只要会话有效,他们就只能访问受保护的资源。

如果没有Web服务器,则必须使用隐式授权。 但这意味着访问令牌暴露于互联网。 如果不可信用户可以访问它,他们可以使用它,直到它到期。 这意味着他们将有权访问它的时间超过授权代码授权。 因此,您可能需要考虑让令牌尽快过期,并避免提供对更敏感资源的访问。





.net oauth mendeley