
上篇了解了如何调用 OAuth 授权来获取数据,本篇介绍如何开放OAuth授权,并控制服务端数据访问。[源码下载] 先看一下图: 这两天事太多,文章整理的断断续续 OK,步入正题,这里还是要借力:DevDefined.OAuth 框架。它提供了客户端访问,服务端管理Token的基
上篇了解了如何调用 OAuth 授权来获取数据,本篇介绍如何开放OAuth授权,并控制服务端数据访问。[源码下载]
先看一下图:

这两天事太多,文章整理的断断续续
OK,步入正题,这里还是要借力: DevDefined.OAuth 框架。它提供了客户端访问,服务端管理Token的基础功能。
1. OAuthChannel
OAuthWebServiceHostFactory 添加拦截器,使用了 WebServiceHost2 (Microsoft.ServiceModel.Web.dll 里,是 Microsoft 发布的WCF REST Starter Kit的一部分)
WebServiceHost2 重写了 ServiceHost 里 OnOpening 方法添加拦截器。WebServiceHost2的源代码猛击这里
OAuthWebServiceHostFactory:
using System;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using Microsoft.ServiceModel.Web;
using DevDefined.OAuth.Provider;
using OAuthChannel.Repositories;
namespace OAuthChannel
{
public class OAuthWebServiceHostFactory : WebServiceHostFactory
{
public IOAuthProvider OAuthProvider { get; set; }
public ITokenRepository AccessTokenRepository { get; set; }
protected override System.ServiceModel.ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var serviceHost = new WebServiceHost2(serviceType, true, baseAddresses);
var interceptor = new OAuthChannel.OAuthInterceptor(OAuthProvider, AccessTokenRepository);
serviceHost.Interceptors.Add(interceptor);
return serviceHost;
}
}
} 拦截器(OAuthInterceptor.cs)将请求的 OAuth (Request Header中) 转换成 OAuthChannel.Models.AccessToken
public class AccessToken : TokenBase
{
public string UserName { get; set; }
public string[] Roles { get; set; }
public DateTime ExpireyDate { get; set; }
}
namespace OAuthWcfRestService
{
public class Contact
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Owner { get; set; }
}
public class DataModel
{
public static List Contacts;
static DataModel()
{
Contacts = new List {
new Contact(){ Id=0, Name="Felix", Email="Felix@test.com", Owner = "jane" },
new Contact(){ Id=1, Name="Wendy", Email="Wendy@test.com", Owner = "jane"},
new Contact(){ Id=2, Name="John", Email="John@test.com", Owner = "john"},
new Contact(){ Id=3, Name="Philip", Email="Philip@mail.com", Owner = "john"}
};
}
}
} namespace OAuthWcfRestService
{
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class OAuthService
{
[WebGet(UriTemplate = "Contacts")]
public List Contacts()
{
var name = Thread.CurrentPrincipal.Identity.Name;
return DataModel.Contacts.Where(c => c.Owner == name).ToList();
}
}
} 在 web.config 中,利用 WCF 对 ASP.NET 的兼容机制,使用 Form 认证:定义了两个用户:john 和 jane
public class Global : HttpApplication
{
void Application_Start(object sender, EventArgs e)
{
RegisterRoutes();
}
private void RegisterRoutes()
{
var oauthWebServiceHostFactory = new OAuthChannel.OAuthWebServiceHostFactory
{
AccessTokenRepository = OAuthServicesLocator.AccessTokenRepository,
OAuthProvider = OAuthServicesLocator.Provider
};
RouteTable.Routes.Add(new ServiceRoute("OAuthService", oauthWebServiceHostFactory, typeof(OAuthService)));
}
}作为一个基本的OAuth授权服务,我们还需要提供:
1. 获取 RequestToken 的服务
2. 获取 AccessToken 的服务
RequestToken.ashx :返回 RequestToken
using System;
using System.Web.UI;
using DevDefined.OAuth.Framework;
using DevDefined.OAuth.Provider;
namespace OAuthWcfRestService
{
public partial class RequestToken : System.Web.IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(System.Web.HttpContext context)
{
IOAuthContext oauthContext = new OAuthContextBuilder().FromHttpRequest(context.Request);
IOAuthProvider provider = OAuthManager.Provider;
IToken token = provider.GrantRequestToken(oauthContext);
context.Response.Write(token);
context.Response.End();
}
}
}using System;
using System.Web.UI;
using DevDefined.OAuth.Framework;
using DevDefined.OAuth.Provider;
namespace OAuthWcfRestService
{
public partial class AccessToken : System.Web.IHttpHandler
{
public bool IsReusable
{
get { return true; }
}
public void ProcessRequest(System.Web.HttpContext context)
{
IOAuthContext oauthContext = new OAuthContextBuilder().FromHttpRequest(context.Request);
IOAuthProvider provider = OAuthManager.Provider;
IToken accessToken = provider.ExchangeRequestTokenForAccessToken(oauthContext);
context.Response.Write(accessToken);
context.Response.End();
}
}
}private void ApproveRequestForAccess(string tokenString)
{
OAuthChannel.Models.RequestToken requestToken = RequestTokenRepository.GetToken(tokenString);
var accessToken = new OAuthChannel.Models.AccessToken
{
ConsumerKey = requestToken.ConsumerKey,
Realm = requestToken.Realm,
Token = Guid.NewGuid().ToString(),
TokenSecret = Guid.NewGuid().ToString(),
UserName = HttpContext.Current.User.Identity.Name,
ExpireyDate = DateTime.Now.AddMinutes(1),
Roles = new string[] { }
};
AccessTokenRepository.SaveToken(accessToken);
requestToken.AccessToken = accessToken;
RequestTokenRepository.SaveToken(requestToken);
}3. 应用

Default.aspx 发起请求获取RequestToken,授权成功后回调 Callback.ashx
namespace OAuthConsumerSample
{
public partial class _Default : Page
{
protected void oauthRequest_Click(object sender, EventArgs e)
{
OAuthSession session = OAuthSessionFactory.CreateSession();
IToken requestToken = session.GetRequestToken();
if (string.IsNullOrEmpty(requestToken.Token))
{
throw new Exception("The request token was null or empty");
}
Session[requestToken.Token] = requestToken;
string callBackUrl = "http://localhost:" + HttpContext.Current.Request.Url.Port + "/Callback.ashx";
string authorizationUrl = session.GetUserAuthorizationUrlForToken(requestToken, callBackUrl);
Response.Redirect(authorizationUrl, true);
}
}
}namespace OAuthConsumerSample
{
public partial class Callback : System.Web.IHttpHandler, System.Web.SessionState.IRequiresSessionState
{
public void ProcessRequest(System.Web.HttpContext context)
{
var session = OAuthSessionFactory.CreateSession();
string requestTokenString = context.Request["oauth_token"];
var requestToken = (IToken)context.Session[requestTokenString];
IToken accessToken = session.ExchangeRequestTokenForAccessToken(requestToken);
context.Session[requestTokenString] = null;
context.Session[accessToken.Token] = accessToken;
context.Response.Redirect("ViewData.ashx?oauth_token=" + accessToken.Token);
}
public bool IsReusable
{
get { return true; }
}
}
}