zoukankan      html  css  js  c++  java
  • [转载]在.NET中实现OAuth身份认证

    在.NET中实现OAuth身份认证

    来源:李会军

    OAuth为开放API的授权提供了一个安全且开放的标准,它的第一个版本发布于2007年,OAuth 2.0协议版本还在处于草稿状态。到现在为止,大多数开放API的互联网站都采用OAuth方式来进行授权,如前一段时间Twitter取消HTTP Basic认证方式而采用OAuth,国内的豆瓣应该是使用OAuth的先行者,而新浪微博开放平台同时支持HTTP Basic和OAuth两种方式。使用OAuth最大的好处在于第三方应用无需知道用户的账号信息(如用户名与密码)就可以申请获得该用户资源的授权。本文首先我会简单介绍一下HTTP Basic认证方式,而后面详细介绍在.NET中如何使用OAuth方式进行认证。

    HTTP Basic认证

    如果采用HTTP Basic认证方式,一般的做法是在HTTP请求头中添加Authorization标头,把用户名和密码装换为Base64编码放在HTTP请求头中,用.NET非常简单的就可以实现,如下代码所示:

    string url = "http://terrylee.me/blog";
    HttpWebRequest request = HttpWebRequest.Create(url) as HttpWebRequest;

    string username = "myusername";
    string password = "mypassword";

    string up = username + ":" + password;
    CredentialCache cache = new CredentialCache();
    cache.Add(new Uri(url), "Basic", new NetworkCredential(username, password));
    request.Credentials = cache;
    request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(new ASCIIEncoding().GetBytes(up)));

    HttpWebResponse response = request.GetResponse() as HttpWebResponse;
    Stream stream = response.GetResponseStream();
    StreamReader reader = new StreamReader(stream, Encoding.UTF8);
    Console.WriteLine(reader.ReadToEnd());

    在发起请求后,可以看到HTTP头中的Authorization标头:


    关于HTTP Basic认证的详细内容大家可以参考RFC2617。可以看到使用HTTP Basic认证的缺点在于第三方应用需要知道用户账号信息,存在着很多的不安全因素。

    OAuth认证

    在使用OAuth认证时,有3个常用的URL需要首先了解一下:

    A. 获取未授权的Request Token B. 请求用户对Request Token授权 C. 使用授权Request Token换取Access Token

    整个认证过程可以分为3步,我们用下面的流程图来表示:



    接下来我们以豆瓣的OAuth认证为例,具体看一下每一步需要做什么。首先可以在http://code.google.com/p/oauth/下载到各种语言实现OAuth类库,因为我们的示例用C#来实现(完整的示例代码在这里能够下载到),所以只用下载到的OAuthBase类就够了,另外在开始之前还需要到豆瓣去创建一个应用,以便能够拿到api_key和api_Secret。

    第一步,获取未授权的Request Token,请求的地址为http://www.douban.com/service/auth/request_token,在这一步里的请求参数oauth_consumer_key就是我们在上面创建应用时得到的api_key,而计算签名使用的Secret也就是上面创建应用时得到的api_secret:

    //1. 获取Request Token,该步骤使用API Key和API Key Secret签名
    public void getRequestToken()
    {
    Uri 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,
    OAuthBase.SignatureTypes.HMACSHA1,
    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_timestamp={0}&", timeStamp);
        sb.AppendFormat("oauth_signature_method={0}&", "HMAC-SHA1");
        sb.AppendFormat("oauth_version={0}&", "1.0");
        sb.AppendFormat("oauth_signature={0}", sig);

    Console.WriteLine("请求Request Token的url: \n" + sb.ToString());

    //请求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();

    Console.WriteLine("请求Request Token的返回值: \n" + responseBody);

    //解析返回的Request Token和Request Token Secret
    Dictionary<string, string> responseValues = parseResponse(responseBody);
        requestToken = responseValues["oauth_token"];
        requestTokenSecret = responseValues["oauth_token_secret"];
    }

    通过这一步我们可以得到Request Token和Request Token Secret。

    第二步,请求用户对Request Token授权,跳转到服务提供方授权页面(本例中指豆瓣http://www.douban.com/service/auth/authorize),在跳转到授权页面时需要传递第一步获取的Request Token。另外,在请求授权页面时还有一个可选参数oauth_callback,指用户授权完全后跳转回的页面,对于Web应用来说,这一步不是什么问题,使用浏览器进行跳转就可以了。但是如果第三方应用是客户端程序,就显的有些麻烦,新浪微博API使用的解决方案是如果第三方应用是客户端应用,则在用户授权完成后,生成一个PIN码,第三方应用会要求用户输入这个PIN码。

    // 2. 用户确认授权
    public void authorization()
    {
    //生成引导用户授权的url
    string url =  authorizationUri + requestToken;

    Console.WriteLine("请将下面url粘贴到浏览器中,并同意授权,同意后按任意键继续:");
    Console.WriteLine(url);
    }

    第三步,使用授权的Request Token换取Access Token,请求的地址为http://www.douban.com/service/auth/access_token,这一步的请求过程与第一步大同小异,唯一不同的地方在于计算签名时需要同时使用创建应用时获取的api_secret和第一步获取的Request Token Secret,在请求的结果中将会包含Access Token和Access Token Secret。

    // 3. 换取Access Token,该步骤使用API Key、API Key Secret、Request Token和Request Token Secret签名
    public void getAccessToken()
    {
    Uri uri = accessTokenUri;
    string nonce = oAuth.GenerateNonce();
    string timeStamp = oAuth.GenerateTimeStamp();
    string normalizeUrl, normalizedRequestParameters;

    // 签名
    string sig = oAuth.GenerateSignature(
            uri,
            apiKey,
            apiKeySecret,
            requestToken,
            requestTokenSecret,
    "GET",
            timeStamp,
            nonce,
    OAuthBase.SignatureTypes.HMACSHA1,
    out normalizeUrl,
    out normalizedRequestParameters);
        sig = HttpUtility.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);

    Console.WriteLine("请求Access Token的url: \n" + sb.ToString());

    //请求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();

    Console.WriteLine("请求Access Token的返回值: \n" + responseBody);

    //解析返回的Request Token和Request Token Secret
    Dictionary<string, string> responseValues = parseResponse(responseBody);
        accessToken = responseValues["oauth_token"];
        accessTokenSecret = responseValues["oauth_token_secret"];
    }

    到这一步为止,整个认证过程就已经完成了。现在有了Access Token和Access Token Secret,就可以访问受限资源了,在计算签名时需要使用创建应用时得到的api_secret和这一步得到的Access Token Secret,OAuth认证信息推荐添加在HTTP请求标头中,如使用豆瓣API发送广播:

    POST http://api.douban.com/miniblog/saying HTTP/1.1
    Authorization: OAuth realm="",
        oauth_consumer_key=0c7c3ca26a68d2ad2574b5e73f3a7807,
        oauth_nonce=8559837,
        oauth_timestamp=1284995469,
        oauth_signature_method=HMAC-SHA1,
        oauth_version=1.0,
        oauth_signature=HmkcQjhd6B3pZ%2fRWkJ23VAxlHKQ%3d,
        oauth_token=136c07ebc88d53ec3a4417c359a7fbc4

    Content-Type: application/atom+xml
    Host: api.douban.com
    Content-Length: 172

    <?xml version='1.0' encoding='UTF-8'?>
    <entry xmlns:ns0="http://www.w3.org/2005/Atom" xmlns:db="http://www.douban.com/xmlns/">
    <content>C# OAuth认证成功</content>
    </entry>

    OAuth的认证过程虽然相比较HTTP Basic稍显有些复杂,但只要弄清楚了整个过程,还是比较简单的,总结起来就是获取Request Token,请求用户授权,换取Access Token三个步骤。

    参考资料:

    1. OAuth官方网站:http://oauth.net/

    2. OAuth规范中文描述:http://www.rollingcode.org/blog/f/oauth-core-1.0-final-cn.html

    3. 豆瓣OAuth认证示例:http://code.google.com/p/douban-oauth-sample/

    4. 豆瓣API OAuth认证:http://www.douban.com/service/apidoc/auth

  • 相关阅读:
    JAVAEE网上商城项目总结
    色盲小游戏
    jQuery(动画效果)
    Oracle exp,imp,expdp,impdp数据导入导出
    Sysbench压力测试工具简介和使用(二)
    Sysbench压力测试工具简介和使用(一)
    Eclipse常用快捷键汇总
    常用数据库连接URL地址大全
    H2数据库使用
    DbVisualizer 解决中文乱码问题
  • 原文地址:https://www.cnblogs.com/fx2008/p/2521148.html
Copyright © 2011-2022 走看看