C# 网络编程之豆瓣OAuth2.0认证具体解释和遇到的各种问题及解决
近期在帮人弄一个豆瓣API应用,在豆瓣的OAuth2.0认证过程中遇到了各种问题,同一时候自己须要一个个的尝试与解决,终于完毕了豆瓣API的訪问.作者这里就不再吐槽豆瓣的认证文档了,毕竟人家也不easy.可是作者发现关于豆瓣OAuth认证过程的文章很之少,所以想具体写这样一篇文章方便后面要做相同东西的人阅读.希望文章对大家有所帮助,尤其是想做豆瓣API开发的刚開始学习的人.
(文章中蓝色字表示官方文档引用,红色字是可能遇到问题及注意,黑色字是作者叙述)
一.误区OAuth1.0认证过程
你遇到的第一个问题可能就是还在阅读"豆瓣
API OAuth认证"这篇官方文档,而且在疯狂的尝试.我就是这样花费了非常长时间研究了OAuth1.0认证过程,但总是错误,由于他已经过时了.你须要使用OAuth2.0完毕认证过程.阅读"使用OAuth2.0訪问豆瓣API"官方文档.
可是OAuth1.0提供的思想还是能够的(安慰自己),并且非常多关于豆瓣博客文档都是基于1.0的认证过程,事实上已经过时.这里也简单讲讲它的基本过程和原理:(OAuth原理和过去Auth1.0认证成果案例)
它主要是通过Google-OAuth项目提供的C#语言的OAuth库,在自己定义OAuth类中有计算签名值oauth_signature方法,签名方法HMAC-SHA1,还有计算时间戳oauth_timestamp等方法,然后在參照DoubanOAuthBasicSample项目完毕它的认证流程,主要方法是getRequestToken、authorization和getAccessToken.
豆瓣OAuth1.0官方文档给出的详细四个步骤:获取未授权的Request Token、请求用户授权Request Token、使用授权后的Request Token换取Access Token、使用 Access Token 訪问或改动受保护资源.详细豆瓣 OAuth1.0认证代码:OAuth类和DoubanOAuthBasicSample
事实上,你仅仅要知道它已经过时,不要在使用该方法就可以.以下才是我想讲述的详细怎样通过C#程序完毕豆瓣的OAuth认证并訪问须要授权的数据.
二.获取autorization_code
首先在你须要參考的详细豆瓣官方文档就是:http://developers.douban.com/wiki/?title=oauth2
使用OAuth2.0流程详细例如以下:(官方文档)
1.应用向豆瓣请求授权
2.豆瓣为用户显示一个授权页面,用户在此页面确认是否允许授权
3.假设用户允许授权,应用汇获取到一个訪问令牌(access_token),通过此令牌用户能够訪问授权数据
4.假设訪问须要授权的Api,请使用https协议,加上access_token的Header.
以下具体解说
首先你须要申请API Key,在完毕申请过程中你须要注意3个值:API Key\Secret\回调地址.后面的程序须要应用,当使用的时候我会具体介绍.因为我是桌面client应用,授权流程为native-application flow.
依据它的详细流程我设计的界面例如以下图所看到的:
获取authorization_code步骤(官方文档)
通过在浏览器中訪问以下地址,来引导用户授权并获取authorization_code.
https://www.douban.com/service/auth2/auth
參数:
client_id 必选參数,应用的唯一标识,相应于APIKey
redirect_uri 必选參数,用户授权完毕后的回调地址,通过回调地址获得用户的授权结果.与注冊一致.
response_type 必选參数,此值能够为code或者token.在本流程中此值为code
scope 可选參数,申请权限的范围,假设不填,则使用缺省的scope.假设申请多个scope,使用逗号分隔
state 可选參数,用来维护请求和回调状态的附加字符串,授权完毕回调时会附加此參数,应用依据此字符串来推断上下文关系.
注意:此请求必须是HTTP GET方式
返回结果:
当用户拒绝授权时,浏览器会重定向到redirect_uri,并附加错误信息
https://www.example.com/back?error=access_denied
当用户允许授权时,浏览器会重定向到redirect_uri,并附加autorization_code
https://www.example.com/back?code=9b73a4248
首先,你须要定义变量例如以下,这些变量都是我们须要使用的.当中APIkey\secret\回调地址填写你自己的,以下的被我改过不是源数据☺(操心丢失)
#region 定义变量
//申请的API Key
public string apiKey = "00489f145c2576bd00d9dd3d147064";
//申请的API 密钥
public string apiKeySecret = "72c36131ace8ea";
//申请的回调地址 我的应用URL
public string myurl = "http://www.baidu.com/";
//获取authorization_code
public Uri GetAuthorizationCode = new Uri("https://www.douban.com/service/auth2/auth");
//获取access_token
public Uri GetAccessToken = new Uri("https://www.douban.com/service/auth2/token");
//浏览器返回autorization_code
public string autorizationCode = "";
//AccessToken授权成功后返回的Json数据
public string accessToken = "";
public string userName = "";
public string userId = "";
public string expiresIn = "";
public string refreshToken = "";
#endregion
然后,点击button1(浏览)按钮,同一时候设计视图中为webBrowser1控件加入�DocumentCompleted事件(右键->属性->'闪电图标'事件).同一时候引用命名空间:using System.Web;\using System.Net;\using System.IO;
#region 第一步 浏览 获取authorization_code
//点击"浏览"显示豆瓣登录界面
private void button1_Click(object sender, EventArgs e)
{
//获取authorization_code构造URL
StringBuilder url = new StringBuilder(GetAuthorizationCode.ToString()); //可变字符串
//追加组合格式字符串
url.AppendFormat("?client_id={0}&", apiKey);
url.AppendFormat("redirect_uri={0}&", myurl);
url.AppendFormat("response_type={0}", "code");
//url.AppendFormat("scope={0}", "scope=shuo_basic_r,shuo_basic_w");
//显示输入URL
textBox1.Text = url.ToString();
string Input = url.ToString();
//将指定URL载入到WebBrowser控件中
webBrowser1.Navigate(Input);
} //文件载入完毕后发生事件
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//获取当前文档URL
string reUrl = this.webBrowser1.Url.ToString();
textBox1.Text = reUrl;
//获取https://www.example.com/back?code=9b73a4248中code值
if (!string.IsNullOrEmpty(reUrl))
{
//获取问号后面字符串
string LastUrl = reUrl.Substring(reUrl.LastIndexOf("?") + 1, (reUrl.Length - reUrl.LastIndexOf("?") - 1));
//依据參数间的&号获取參数数组 能够获取多个參数此时仅仅需一个code
string[] urlParam = LastUrl.Split('&');
foreach (string s in urlParam)
{
//将參数名与參数值赋值给数组 value[0]參数名称 value[1]參数值
string[] value = s.Split('=');
//MessageBox.Show("參数名称为:" + value[0] + " 參数值为:" + value[1]);
if (value[0] == "code")
{
autorizationCode = value[1];
}
}
}
//输出获取code值
if (autorizationCode != "") MessageBox.Show(autorizationCode);
}
#endregion
执行结果例如以下图所看到的,填写完用户邮箱和password,点击授权后获取autorization_code例如以下:
这里你须要注意的有一下几点:
1.为什么我的回调地址设置为"http://www.baidu.com/"?
最初我设置的回调地址为自己定义的一个网址,可是输入邮箱和password后点击授权,总是HTTP 400错误,啥都不能获取.使用IE浏览器也是一样,可是google能获取.后来经过同学提醒(他做腾讯API,资料多,官方文档规范)可能回调地址须要能訪问的网址,所以改成了百度,而且成功获取.由于这一步仅仅须要获取code值,网址并不关键.(可能也有没考虑到的地方)
2.你须要知道该程序中必须使用GET方法=浏览能够直接訪问.(除设置header,后面讲述)
在程序中我是直接调用webBrowser1.Navigate(Input);函数訪问的,也能够使用GET方法訪问.GET和POST的差别是你须要知道的,简单来说就是GET后面给的网址參数显示,而POST是隐式的.
程序和文档中说道的採用GET的方法,并带有參数的都是这样连接的.url+?+參数=參数值&參数=參数值...正如获取code中的URL,它通过浏览器是能够直接訪问的.
https://www.douban.com/service/auth2/auth?client_id=00489f145c2576bd00d9dd3d147064&redirect_uri=http://www.baidu.com/&response_type=code
3.你可能会遇到的错误是113 缺少參数required_parameter_is_missing.
此时你在设置url时,通过StringBuilder可变字符串添加�參数时,须要把全部的必须的參数填写.同一时候,注意你的&和?是否正确填写.你能够參考的官方文档错误报告例如以下:
http://developers.douban.com/wiki/?title=oauth2
http://developers.douban.com/wiki/?title=api_v2
此时,你的第一步获取code已经完毕,接下来是获取access_token的过程.
三.获取access_token
官方文档接受的获取access_token例如以下:
https://www.douban.com/service/auth2/token
參数:
client_id 必选參数,应用的唯一标识,相应于APIKey
client_sercet 必选參数,应用的唯一标识,相应于豆瓣secret
redirect_url 必选參数,用户授权后的回调地址
grant_type 必选參数,此值可为authorization_code或者refresh_token,此时为authorization_code
code 必选參数,上一步中获取的authorization_code
注意:此请求必须是HTTP POST方式
返回结果为Json格式数据例如以下图所看到的
//获取的数据装换为Json格式 此时返回的json格式的数据
{
"access_token":"0e63c03dfb66c4172b2b40b9f2344c",
"douban_user_name":"Eastmount",
"douban_user_id":"57279898",
"expires_in":604800,
"refresh_token":"84406d40cc58e0ae8cc147c2650aa2",
}
当中你须要注意的是四个地方:
1.怎样使用POST方法发送请求获取应答,这再也不是通过浏览器就能直接訪问的问题.
2.获取的JSON格式数据怎样通过C#解析.
3.可能你的訪问不成功,你须要在"我的应用"中加入�測试用户.看看自己的是否加入�.
4.你可能遇到101 错误的请求方法,invalid_request_method: GET由于你须要採用POST方法.
我解说怎样解析JSON格式的数据,这里參照非常多人可能都使用过的方法.
你须要下载Newtonsoft.Json.dll文件并加入�引用它,參考百度"C#使用json字符串"方法,最好先把该dll放置到C:\WINDOWS\Microsoft.NET\Framework目录中,里面有非常多dll(我的程序是VS2012
.NET4.5).
在"解决方式"中鼠标右键引用->加入�引用->浏览->加入�该dll.然后加入�命名空间using Newtonsoft.Json.Linq;将POST方法获取应答string转换为JSON格式转换赋值就可以.详细代码例如以下,同一时候POST方法发送HTTP请求我是通过自己定义函数sendMessage实现的.载入button2(授权)按钮事件.
#region 第二步 授权 获取access_token
private void button2_Click(object sender, EventArgs e)
{
//显示输入URL
textBox1.Text = GetAccessToken.ToString();
//获取access_token构造POST參数
StringBuilder url = new StringBuilder(""); // 可变字符串
//追加组合格式字符串
url.AppendFormat("client_id={0}&", apiKey);
url.AppendFormat("client_secret={0}&", apiKeySecret);
url.AppendFormat("redirect_uri={0}&", myurl);
url.AppendFormat("grant_type={0}&", "authorization_code");
url.AppendFormat("code={0}", autorizationCode);
//获取POST提交数据返回内容
string AccessContent = sendMessage(GetAccessToken.ToString(), url.ToString());
webBrowser1.DocumentText = AccessContent;
//获取的数据装换为Json格式 此时返回的json格式的数据
JObject obj = JObject.Parse(AccessContent);
accessToken = (string)obj["access_token"]; //access_token
userName = (string)obj["douban_user_name"]; //豆瓣username
userId = (string)obj["douban_user_id"]; //用户id
expiresIn = (string)obj["expires_in"]; //生命周期 604800秒=7天
refreshToken = (string)obj["refresh_token"]; //刷新令牌
MessageBox.Show(accessToken + "\n" + userName + "\n" +
userId + "\n" + expiresIn + "\n" + refreshToken);
} //发送消息Post方法
public static string sendMessage(string strUrl, string PostStr)
{
try
{
//设置消息头
CookieContainer objCookieContainer = null;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(strUrl);
request.Method = "Post";
request.ContentType = "application/x-www-form-urlencoded";
request.Referer = strUrl;
if (objCookieContainer == null)
objCookieContainer = new CookieContainer(); request.CookieContainer = objCookieContainer;
byte[] byteData = Encoding.UTF8.GetBytes(PostStr.ToString().TrimEnd('&'));
request.ContentLength = byteData.Length;
using (Stream reqStream = request.GetRequestStream())
{
reqStream.Write(byteData, 0, byteData.Length);
}
//Response应答流获取数据
string strResponse = "";
using (HttpWebResponse res = (HttpWebResponse)request.GetResponse())
{
objCookieContainer = request.CookieContainer;
using (Stream resStream = res.GetResponseStream())
{
using (StreamReader sr = new StreamReader(resStream, Encoding.UTF8)) //UTF8
{
strResponse = sr.ReadToEnd();
}
}
// res.Close();
}
return strResponse;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Console.Read();
}
return null;
}
#endregion
执行程序,点击"浏览"授权成果后在点击"授权"的执行结果例如以下图所看到的:
四.使用access_token
通过前面的步骤我们已经获取了access_token数据,那么如何使用它呢?当我看到豆瓣给出的使用官方文档例如以下时:
curl "https://api.douban.com/v2/user/~me"
-H "Authorization: Bearer a14afef0f66fcffce3e0fcd2e34f6ff4"
我非常头痛啊!那么,如何通过C#实现使用access_token訪问要授权的数据呢?
GET https://api.douban.com/v2/user/~me
该URL是获取当前授权用户信息的,须要必须先进行API认证授权,返回的是当前授权用户信息.因此,使用它全然能够验证授权成果后的操作.详细代码例如以下:
#region 第三步 豆瓣訪问授权数据
private void button3_Click(object sender, EventArgs e)
{
try
{
//获取当前授权用户信息 须要必须先进行API认证授权,返回当前授权的UserInfo
string Input = "https://api.douban.com/v2/user/~me";
textBox1.Text = Input;
//HttpWebRequest对象实例:该类用于获取和操作HTTP请求
var request = (HttpWebRequest)WebRequest.Create(Input); //Create:创建WebRequest对象
//设置请求方法为GET
request.Headers.Add("Authorization", "Bearer " + accessToken);
request.Method = "GET";
//HttpWebResponse对象实例:该类用于获取和操作HTTP应答
var response = (HttpWebResponse)request.GetResponse(); //GetResponse:获取答复
//构造数据流对象实例
Stream stream = response.GetResponseStream(); //GetResponseStream:获取应答流
StreamReader sr = new StreamReader(stream); //从字节流中读取字符
//从流当前位置读取到末尾并显示在WebBrower控件中
string content = sr.ReadToEnd();
webBrowser1.DocumentText = content;
//关闭响应流
stream.Close();
sr.Close();
response.Close();
}
catch (Exception msg) //异常处理
{
MessageBox.Show(msg.Message);
}
}
#endregion
执行结果例如以下图所看到的:
不要以为这简单的几句代码就非常easy实现了訪问数据,事实上你须要注意一下几点:
1.你可能会遇到1000错误 须要权限need_permission?
那时你须要在訪问时设置header,加入�-H "Authorization: Bearer a14afef0f66fcffce3e0fcd2e34f6ff4".採用C#设置标题头的详细代码例如以下:
request.Headers.Add("Authorization", "Bearer " + accessToken);
当中你须要注意Bearer后面的空格.并且有同学说他在使用网盘认证时,获取的方法有两种,一种是设置header,一种是在URL后面加上?access_token=值就可以.但我測试了下豆瓣仅仅有设置header能够.
2.认证过程已经具体叙述了,增删改查其它数据影片信息、用户信息、评论、收藏、关注等方法都类似,感兴趣的能够自己完毕.它的具体设置參数參照豆瓣文档:http://developers.douban.com/wiki/?title=api_v2
五.总结
最后总结下它的详细步骤,事实上它就是依照豆瓣的文档完毕的,三个步骤:获取authorization_code、获取access_token和使用access_token.你也不能说豆瓣文档讲得不好,事实上实质东西它都讲述清除了.须要的仅仅是你自己的探索,可能刚接触比較新奇和难,但事实上完毕后就发现它非常easy.
希望该文章对大家有所帮助,尤其是想做豆瓣API开发的而且使用C#的,这方面资料比較少,基本都是php和java的.更希望同学能从该文章中学到一下几个东西:
1.怎样通过官方文档完毕一个东西,可能遇到的问题都须要自己解决,而不是复制粘贴.
2.怎样使用C#网络编程GET和POST两种方法HTTP请求并获取应答.
3.怎样使用C#解析Json格式的数据.
4.怎样使用OAuth认证API开发,这方面腾讯、新浪等比較完好.
最后也感谢豆瓣网带给我非常多知识,推荐程序猿也看看文学书籍,如《文学回顾录》和《季羡林 清华园日记》,生活不仅仅有编程啊.假设有错误或不足之处,还请海涵.
源码免费下载地址:http://download.csdn.net/detail/eastmount/7399075
(By:Eastmount 2014-5-25 下午6点 原创CSDNhttp://blog.csdn.net/eastmount/)
C# 网络编程之豆瓣OAuth2.0认证具体解释和遇到的各种问题及解决的更多相关文章
- Oauth2.0 认证的Web api例子
Oauth2.0的解释 OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容.OA ...
- .Net WebApi 实现OAuth2.0认证
现在多数公众平台提供的api都使用OAuth2.0认证模式,最近在搞Android方面的开发,身份认证和权限控制的各方面比较来说,使用OAuth认证的还是比较靠谱,OAuth2.0的协议可以参考htt ...
- Owin中间件搭建OAuth2.0认证授权服务体会
继两篇转载的Owin搭建OAuth 2.0的文章,使用Owin中间件搭建OAuth2.0认证授权服务器和理解OAuth 2.0之后,我想把最近整理的资料做一下总结. 前两篇主要是介绍概念和一个基本的D ...
- 使用Owin中间件搭建OAuth2.0认证授权服务器
前言 这里主要总结下本人最近半个月关于搭建OAuth2.0服务器工作的经验.至于为何需要OAuth2.0.为何是Owin.什么是Owin等问题,不再赘述.我假定读者是使用Asp.Net,并需要搭建OA ...
- OAuth2.0认证介绍
OAuth2.0鉴权 返回 目录 [隐藏] 1 腾讯微博OAuth2.0认证介绍 2 获取accesstoken的两种方式 2.1 1.Authorization code grant 2.1.1 第 ...
- OAuth2.0认证详解
目录 什么是OAuth协议 OAuth2.0是为了解决什么问题? OAuth2.0成员和授权基本流程 OAuth2.0成员 OAuth2.0基本流程 什么是OAuth协议 OAuth 协议为用户资源的 ...
- Spring Cloud Zuul 网关使用与 OAuth2.0 认证授权服务
API 网关的出现的原因是微服务架构的出现,不同的微服务一般会有不同的服务地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题: 客户端会 ...
- QQ登录整合/oauth2.0认证-04-调整到QQ互联进行QQ登录
---------------------------------目录------------------------------------- QQ登录整合/oauth2.0认证-03-对第二节的代 ...
- QQ登录整合/oauth2.0认证-03-对第二节的代码改进
---------------------------目录---------------------------------- QQ登录整合/oauth2.0认证-01-申请appkey和appid ...
随机推荐
- poj3270Cow Sorting(置换)
链接 对于组合数学是一点也不了解 讲解 重要一点 要知道一个循环里最少的交换次数是m-1次 . #include <iostream> #include<cstdio> #in ...
- volicety常用方法
1.volicety得到某个元素的个数 $extendsInfos.size() 2.volicety 布尔值判断: 如果a为null,#if($a) ,产生的判断值是false 等同于#if(fa ...
- window国际化文案
越来越多的程序支持多语言切换,或者能自动适应当前系统语言,让自己开发的程序支持多语言不仅可以让自己的程序被国人使用,也能让外国程序爱好者使用.VC开发多语言程序有多种方法,或读取配置文件,或使用不同资 ...
- Dataguard Content
1.Dataguard环境设计的三个重要概念 1.1 Primary数据库 在Data Guard的环境中与Standby数据库对应的数据库即是Primary数据库,也就是Primary数据库正在运行 ...
- 【转】如何把ndk编译出来的可执行文件伪装成so打包到apk中
原文网址:http://jeyechao.iteye.com/blog/2164286 ndk编译出来的共享库,eclipse会自动打包到apk中,而编译出来的可执行文件则不会. 要想可执行文件自动被 ...
- Erlang入门(二)—并发编程
Erlang中的process——进程是轻量级的,并且进程间无共享.查了很多资料,似乎没人说清楚轻量级进程算是什么概念,继续查找中...闲话不提,进入并发编程的世界.本文算是学习笔记,也可以说是< ...
- The type or namespace name '****' could not be found (are you missing a using directive or an assembly reference
错误的提升内容:
- SourceGrid zt
SourceGrid介绍和使用及实例举例 先上图,来一个简单演示: SourceGrid就是一个用于数据显示的表格控件,这个控件比c#自带的 DataGridView要强大很多,先不说他的原理,只说他 ...
- 2015年10月23日JS笔记
ECMAScript标准:JavaScript核心语法 微软:Jscript ECMAScript标准:一纸空文 JavaScript和JScritp都号称完全实现了 ECMAScript标准 W3C ...
- Fidder的几点补充
坦克兄写的Fiddler教程很好很详细 链接这里:http://www.cnblogs.com/TankXiao/archive/2012/02/06/2337728.html 补充一: Fiddle ...