新浪微博开放平台OAuth授权解决方案(含代码)

  前几日一位朋友项目中需要使用新浪微博的接口,故和这位朋友一同研究了新浪微博开放平台上面所提供的资料,首先要使用这些接口是需要用户登录并且授权的,新浪微博开放平台其实是提供两种授权方式的,第一种是:OAuth授权方式,第二种是:HTTP普通鉴权方式,我们使用了第一种方式来授权,但是在执行过程中遇到了许多问题,觉得单对新浪微博开放平台还是有一些代表性,所以共享下经验,下面可以下载我的Demo。

  OAuth是一种国际授权方式,它不需要用户在第三方应用输入用户名及密码,所以安全性很高,那么在新浪微博开放平台中通过OAuth授权的流程图是这样的:

  其实在程序中步骤表现就只有4步:

                                      1、获取Request token。

               2、用户认证。

               3、获取Access token。

               4、获取用户信息。

  在处理OAuth授权过程中我也碰到几个在新浪开放平台论坛中常见的几个问题,在这里总结下,在后面讲解中会讲到我的想法和解决办法:

               1、requesttoken时callback问题。

               2、401错误。

               3、403错误。

               4、500错误。

               5、未经授权错误。

  在这里顺便讲一下调用新浪微博接口必须是要申请一个应用的,申请应用成功之后会得到一个App key号和App Secret号,我们也需要通过这两个参数来请求授权,还有就是网上有OAuthBase下载,但是要下对版本,我的Demo中也有,我们的授权主要的代码是在OAuthBase.cs文件中的。

  1、获取Request token:

    直接上代码:

public void getRequestToken()
    {
        Uri uri = new Uri(requestTokenUri);
        string nonce = oAuth.GenerateNonce();//获取随机生成的字符串,防止攻击
        string timeStamp = oAuth.GenerateTimeStamp();//发起请求的时间戳
        string normalizeUrl, normalizedRequestParameters;
        // 签名
        string sig = oAuth.GenerateSignature(uri, apiKey, apiKeySecret, string.Empty, string.Empty, 
           "GET", timeStamp, nonce, string.Empty, out normalizeUrl, out normalizedRequestParameters);
        sig = HttpUtility.UrlEncode(sig);
        //构造请求Request Token的url
        StringBuilder sb = new StringBuilder(uri.ToString());
        sb.AppendFormat("?oauth_consumer_key={0}&", apiKey);
        sb.AppendFormat("oauth_nonce={0}&", nonce);
        sb.AppendFormat("oauth_signature={0}&", sig);
        sb.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
        sb.AppendFormat("oauth_timestamp={0}&", timeStamp);
        sb.AppendFormat("oauth_version={0}", "1.0");
        //请求Request Token
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(sb.ToString());
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        StreamReader stream = new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8);
        string responseBody = stream.ReadToEnd();
        stream.Close();
        response.Close();
        int intOTS = responseBody.IndexOf("oauth_token=");
        int intOTSS = responseBody.IndexOf("&oauth_token_secret=");
        Session["oauth_token"] = responseBody.Substring(intOTS + 12, intOTSS - (intOTS + 12));
        Session["oauth_token_secret"] = responseBody.Substring((intOTSS + 20), responseBody.Length - (intOTSS + 20));
        Response.Redirect(AUTHORIZE + "?oauth_token=" + Session["oauth_token"] + "&oauth_callback=" + Request.Url);
    }

   我在请求Request token的时候遇到了401错误地址返回错误,地址返回错误比较好解决,一般都是地址错误,所以我直接用了Request.Url,那么401错误了我出错是在签名 的地方,最开始的OAuthBase文件下载错了,下给最新的就可以了,还有就是在请求参数中的oauth_version参数,有很多值是1.0a,这样好像是不行的,全部改成1.0就能避免很多错误。

 

  2、用户认证:

   在Request token请求成功之后,平台自动跳到登录页面,进行用户认证,认证通过之后平台会将oauth_token和oauth_verifier返回到指定的callback来,将两个参数保存下来用于请求Access token,在这里如果地址不正确是会报错的。

  3、获取Access token:

     这个请求的重点还是在签名,必须要将用户认证后返回的oauth_token和oauth_verifier一并签名才能正确,有些OAuthBase中是没有将verifier加入签名当中当时让我好生郁闷,如果这点错了应该会报未经授权或者403错误,请求成功之后需要将oauth_token和oauth_token_secret重新保存下,下面是代码:

public void getAccessToken(string requestToken, string oauth_verifier)
    {
        Uri uri = new Uri(ACCESS_TOKEN);
        string nonce = oAuth.GenerateNonce();
        string timeStamp = oAuth.GenerateTimeStamp();
        string normalizeUrl, normalizedRequestParameters;
        // 签名
        string sig = oAuth.GenerateSignature(
        uri,
        apiKey,
        apiKeySecret,
        requestToken,
        Session["oauth_token_secret"].ToString(),
        "Get",
        timeStamp,
        nonce,
        oauth_verifier,
        out normalizeUrl,
        out normalizedRequestParameters);
        sig = oAuth.UrlEncode(sig);
        //构造请求Access Token的url
        StringBuilder sb = new StringBuilder(uri.ToString());
        sb.AppendFormat("?oauth_consumer_key={0}&", apiKey);
        sb.AppendFormat("oauth_nonce={0}&", nonce);
        sb.AppendFormat("oauth_timestamp={0}&", timeStamp);
        sb.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
        sb.AppendFormat("oauth_version={0}&", "1.0");
        sb.AppendFormat("oauth_signature={0}&", sig);
        sb.AppendFormat("oauth_token={0}&", requestToken);
        sb.AppendFormat("oauth_verifier={0}", oauth_verifier);
        //请求Access Token
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(sb.ToString());
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        StreamReader stream = new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8);
        string responseBody = stream.ReadToEnd();
        stream.Close();
        response.Close();
        int intOTS = responseBody.IndexOf("oauth_token=");
        int intOTSS = responseBody.IndexOf("&oauth_token_secret=");
        int intUser = responseBody.IndexOf("&user_id=");
        Session["oauth_token"] = responseBody.Substring(intOTS + 12, intOTSS - (intOTS + 12));
        Session["oauth_token_secret"] = responseBody.Substring((intOTSS + 20), intUser - (intOTSS + 20));
        Session["User_Id"] = responseBody.Substring((intUser + 9), responseBody.Length - (intUser + 9));
        verify_credentials();
    }

  4、获取登录用户信息:

  步骤简单和以上几个请求方式也一样,主要是要将oauth_token和oauth_token_secret加入签名,下面是代码:

    public void verify_credentials()
    {
        Uri uri = new Uri("http://api.t.sina.com.cn/account/verify_credentials.xml");
        string nonce = oAuth.GenerateNonce();
        string timeStamp = oAuth.GenerateTimeStamp();
        string normalizeUrl, normalizedRequestParameters;
        // 签名
        string sig = oAuth.GenerateSignature(
        uri,
        apiKey,
        apiKeySecret,
        Session["oauth_token"].ToString(),
        Session["oauth_token_secret"].ToString(),
        "Get",
        timeStamp,
        nonce,
        string.Empty,
        out normalizeUrl,
        out normalizedRequestParameters);
        sig = HttpUtility.UrlEncode(sig);
        StringBuilder sb = new StringBuilder(uri.ToString());
        sb.AppendFormat("?oauth_consumer_key={0}&", apiKey);
        sb.AppendFormat("oauth_nonce={0}&", nonce);
        sb.AppendFormat("oauth_timestamp={0}&", timeStamp);
        sb.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
        sb.AppendFormat("oauth_version={0}&", "1.0");
        sb.AppendFormat("oauth_signature={0}&", sig);
        sb.AppendFormat("oauth_token={0}&", Session["oauth_token"].ToString());
        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(sb.ToString());
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        StreamReader stream = new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8);
        string responseBody = stream.ReadToEnd();
        stream.Close();
        response.Close();
        Session["responseBody"] = responseBody;
    }

到这里你可以获取用户的个人信息,那么OAuth授权也就成功,其实步骤是比较简单的,主要要注意的就是签名,签名不正确一定是通过不了的,还有就是一些细节,如地址,版本号,请求方式这些细心点就能避免,由于时间原因这里讲的比较简单,希望大家互相交流下,这里是Demo:SinaOAuthSinaOAuth

标签: Asp.Net
posted @ 2011-01-25 17:05 勤劳的渔网工作者 阅读(10611) 评论(32) 编辑 收藏

 回复 引用 查看   
#1楼2011-01-25 18:15 | 周 金根      
官方网站的SDK页面下提供了C#的非官方Demo下载,我试过了可以连接。顶一个,希望看到你写的应用并与大家分享!
 回复 引用 查看   
#2楼2011-01-25 18:30 | Mainz      
源码打不开
 回复 引用 查看   
#3楼2011-01-25 21:56 | MicroCoder      
mark 最近需要做第三方登录
 回复 引用 查看   
#4楼2011-01-25 23:44 | shaoyun      
现在讨论这个慢慢多起来了!新浪的微博做的还是不错!我写了个客户端,不过都是自己在用!
 回复 引用 查看   
#5楼[楼主]2011-01-26 09:29 | 勤劳的渔网工作者      
@周 金根
恩,这个是帮朋友研究的,以后研究应用一定会分享的。

 回复 引用 查看   
#6楼[楼主]2011-01-26 09:29 | 勤劳的渔网工作者      
@Mainz
VS2005的。

 回复 引用 查看   
#7楼2011-01-26 09:44 | finesite      
正在研究,请教一个问题: 如果用户用sina账号登录第三方网站后,获取的Access token和secret是不是唯一的,也就是说以后每次登录该网站都是一样的Access token? 另外针对这种情况的登录,如何关联存储用户在第三方网站的个人信息,比如昵称,出生年月等,就像用qq登录京东商城那样. 谢谢解答
 回复 引用 查看   
#8楼[楼主]2011-01-26 10:41 | 勤劳的渔网工作者      
@finesite
据我了解Access token值每次都是不一样的,因为它是一种安全机制,所以不会每次同一个用户是一样的。对于第三方网站的个人信息问题我觉得你是可以和新浪返回回来的用户ID作为关联来进行你自己的操作。

 回复 引用 查看   
#9楼2011-01-26 11:27 | omeweb      
是的,不一样,不过sina的确是一样的,除非你end session掉,我的微博小工具站 http://omeweb.com/,全面支持sina,QQ微博,sohu的人少,不想搞,目前屏蔽了QQ的接入方式,因为sina的在审核应用,不让有QQ的,NND
引用勤劳的渔网工作者:
@finesite
据我了解Access token值每次都是不一样的,因为它是一种安全机制,所以不会每次同一个用户是一样的。对于第三方网站的个人信息问题我觉得你是可以和新浪返回回来的用户ID作为关联来进行你自己的操作。


 回复 引用 查看   
#10楼2011-01-26 11:29 | omeweb      
授权有3步,xauth只要一步,目前我有自己写了个类库,全部封装了这个过程,使用起来比较简单,年后公开代码
 回复 引用 查看   
#11楼[楼主]2011-01-26 13:46 | 勤劳的渔网工作者      
@阿 强
能否提供代码让大家交流学习一下!

 回复 引用 查看   
#12楼[楼主]2011-01-26 15:45 | 勤劳的渔网工作者      
@阿 强
恩,不失为一种好方法,不过我还不会,呵呵。

 回复 引用 查看   
#13楼2011-01-27 09:33 | finesite      
引用勤劳的渔网工作者:
@finesite
据我了解Access token值每次都是不一样的,因为它是一种安全机制,所以不会每次同一个用户是一样的。对于第三方网站的个人信息问题我觉得你是可以和新浪返回回来的用户ID作为关联来进行你自己的操作。


谢谢答复:
1.我说的第三方网站指的是我目前开发的网站,试着支持sina微博、qq微博和站内登录的方式,前两种的登录方式进去后如何与用户在本站的注册信息关联,比如用户名,出生年月,居住地等,就像qq账号登录京东商城
2.如果Access token的值,每次登录都有变化,那该存储哪个值来记录用户的登录历史
3.Access token值,园子里一位大哥说是不变的,我跟踪一下看看

 回复 引用 查看   
#14楼2011-02-21 22:38 | hahajcs      
请教下楼主,是否用过Xauth认证方式,我在做android做sina客户端的开发时遇到点疑问,在生成签名是使用HMAC_SHA1算法中,用到consumer_secret和oauth_token_secret连接起来,中间用&分割(这是准备密钥的方法),这里在sina官方的说明里说可以跳过oauth的请求步骤,但是跳过那两次请求步骤了,oauth_token_secret从哪儿获取呢?还是不许要哪个值。直接用consumer_sercret做密钥呢?请赐教,谢谢。
 回复 引用 查看   
#15楼[楼主]2011-02-22 17:02 | 勤劳的渔网工作者      
@hahajcs
XAuth认证我没做过,但是oauth_token_secret这个参数应该还是要的,也是要先获得oauth_token_secret和oauth_token再去做操作!

 回复 引用 查看   
#16楼2011-02-23 08:46 | Hurry Jiang      
我好迷茫呀,sina的登录怎么始终登录不了呀!
我在SAE上面添加了一个应用,正在开发,有
access key: 和secret key:
我应该怎样咋Java工程里面实现登录呀?望高手解答.万分感谢!

 回复 引用 查看   
#17楼[楼主]2011-02-23 09:02 | 勤劳的渔网工作者      
@Hurry Jiang
你到开放平台去下个Java的SDK下来看一下,那上面应该有你想要的东西!

 回复 引用 查看   
#18楼2011-02-23 14:06 | hahajcs      
谢谢楼主,sina的我已经通过了,不知楼主做过twitter的没有,我之前做过oauth认证,sina和twitter是一样的,不知XAuht方式也一样。
 回复 引用 查看   
#19楼[楼主]2011-02-23 19:25 | 勤劳的渔网工作者      
@hahajcs
twitter的没有做过,这个只是帮朋友解决的,觉得有些代表才发的博客,现在也没搞这块了。

 回复 引用 查看   
#20楼2011-04-27 10:36 | jj99010      
hi~~我想试着发微博,我新添加一个方法,所有代码和verify_credentials()这个一样,就是把uri 改了,这样提交请求应该是返回一个错误:内容为空。
但是她直接返回说我认证失败。请问您有发微薄的实例么?

 回复 引用 查看   
#21楼2011-07-01 18:56 | kedee      
我做了个DEMO:http://connect.88kuka.com

可以登陆,登陆后发布微博

 回复 引用 查看   
#22楼2011-07-14 07:45 | Kevin Lin      
@kedee
请问,怎么获取全部粉丝名单?
我看api中好像只是获取前20名粉丝...谢谢

 回复 引用 查看   
#23楼2011-07-14 09:04 | kedee      
@Kevin Lin
这个就只能看API文档里,有接口就可以调用,目前我没有使用到这个接口

 回复 引用 查看   
#24楼2011-07-15 14:03 | liuweishow      
我授权为什么总是401错误?
 回复 引用 查看   
#25楼2011-07-18 08:55 | liuweishow      
是不是每次授权获取到的token和token_secret的值都是不一样的呢?我测试很多次了,都是这样子的,那怎么在服务器端保存用户授权的状态呢?
 回复 引用 查看   
#26楼2011-08-04 15:52 | DreamFly2011      
灰常感谢楼主的大无私的分享精神啊,我研究了很久都没有弄出来,直到看到楼主的demo
 回复 引用 查看   
#27楼[楼主]2011-08-05 08:43 | 勤劳的渔网工作者      
@DreamFly2011
客气

 回复 引用 查看   
#28楼2011-09-16 13:41 | webglcn      
学习
 回复 引用 查看   
#29楼2011-12-07 10:19 | 阿蓝哥      
正好需要呢! 谢谢楼主分享!
 回复 引用 查看   
#30楼[楼主]2011-12-07 10:27 | 勤劳的渔网工作者      
@阿蓝哥
客气!

 回复 引用 查看   
#31楼2011-12-27 12:13 | fangwei1688      
非常感谢!敬佩园主的无私精神。 我自己做的可以用了,但问题多多,正好参考别人是怎么做的
 回复 引用 查看   
#32楼2012-02-19 09:54 | 传说二零一二      
膜拜大神,我一直不懂怎么取id和screen_name这两个值,总算找到一篇文章介绍能取值了,感谢园主无私精神!