[转载]在.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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
.NET Core 实现 OAuth2,可以使用 IdentityServer4 这个第三方库。IdentityServer4 是一个基于 OpenID Connect 和 OAuth2 协议的身份认证和授权框架。以下是实现步骤: 1. 安装 IdentityServer4 使用 NuGet 安装 IdentityServer4 包: ``` Install-Package IdentityServer4 ``` 2. 配置 OAuth2 在 Startup.cs 文件的 ConfigureServices 方法,添加 IdentityServer4 服务: ```csharp services.AddIdentityServer() .AddInMemoryClients(new List<Client>()) .AddInMemoryApiResources(new List<ApiResource>()) .AddInMemoryIdentityResources(new List<IdentityResource>()) .AddTestUsers(new List<TestUser>()); ``` 这里使用了 InMemory 存储,也可以使用其他存储方式,如数据库存储。需要添加客户端、API 资源、身份资源和测试用户。 3. 配置授权 在 Startup.cs 文件的 Configure 方法,添加 IdentityServer4 间件: ```csharp app.UseIdentityServer(); ``` 然后,可以在控制器添加 [Authorize] 属性来保护需要授权的 API。 4. 获取访问令牌 客户端可以使用 OAuth2 的授权码模式或者密码模式来获取访问令牌。这里以授权码模式为例: 客户端首先重定向到 IdentityServer4 的授权页面: ``` https://localhost:5001/connect/authorize?client_id=client&response_type=code&redirect_uri=https%3A%2F%2Flocalhost%3A5002%2Fsignin-oidc&scope=api1 openid&state=123456 ``` 用户登录并授权后,将重定向回客户端的回调地址,并在 URL 包含授权码。客户端使用这个授权码来获取访问令牌: ```csharp var client = new HttpClient(); var tokenResponse = await client.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest { Address = "https://localhost:5001/connect/token", ClientId = "client", ClientSecret = "secret", RedirectUri = "https://localhost:5002/signin-oidc", Code = code, }); var accessToken = tokenResponse.AccessToken; ``` 以上是简单的 OAuth2 实现过程,在实际应用需要根据具体业务需求进行更加详细的配置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值