Heim  >  Artikel  >  Datenbank  >  OAuth 学习(2) 自定义OAuth服务端(WCF REST数据访问控制)

OAuth 学习(2) 自定义OAuth服务端(WCF REST数据访问控制)

WBOY
WBOYOriginal
2016-06-07 15:27:371300Durchsuche

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

上篇了解了如何调用 OAuth 授权来获取数据,本篇介绍如何开放OAuth授权,并控制服务端数据访问。[源码下载]
先看一下图:

OAuth 学习(2)  自定义OAuth服务端(WCF REST数据访问控制)

这两天事太多,文章整理的断断续续OAuth 学习(2)  自定义OAuth服务端(WCF REST数据访问控制)

OK,步入正题,这里还是要借力: DevDefined.OAuth 框架。它提供了客户端访问,服务端管理Token的基础功能。

1. OAuthChannel
定义了服务端用户模型,OAuth的拦截器,OAuthWebServiceHostFactory(继承于WebServiceHostFactory,用于添加拦截器),以及 RequestToken 和 AccessToken 保持在内存里的容器及存取类 (InMemoryTokenRepository,InMemoryTokenStore)
OAuth 学习(2)  自定义OAuth服务端(WCF REST数据访问控制)

OAuthWebServiceHostFactory 添加拦截器,使用了 WebServiceHost2 (Microsoft.ServiceModel.Web.dll 里,是 Microsoft 发布的WCF REST Starter Kit的一部分)
WebServiceHost2 重写了 ServiceHost 里 OnOpening 方法添加拦截器。WebServiceHost2的源代码猛击这里
OAuthWebServiceHostFactory:

<pre class="brush:php;toolbar:false">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<oauthchannel.models.accesstoken> 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;
        }
    }
}</oauthchannel.models.accesstoken>

拦截器(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; }
}



2. OAuth WCF Rest Service
首先创建一个 WCF Rest Service:
OAuth 学习(2)  自定义OAuth服务端(WCF REST数据访问控制)
定义一个基础数据模型,供Sample访问:
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<contact> Contacts;

        static DataModel()
        {
            Contacts = new List<contact> {
              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"}
            };
        }
    }
}</contact></contact>
Contacts 中的数据只有属于 Owner 的“用户”才可以访问,因此 OAuthService 中实现如下:
namespace OAuthWcfRestService
{
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class OAuthService
    {
        [WebGet(UriTemplate = "Contacts")]
        public List<contact> Contacts()
        {
            var name = Thread.CurrentPrincipal.Identity.Name;
            return DataModel.Contacts.Where(c => c.Owner == name).ToList();
        }        
    }
}</contact>
上面的 name 从 Thread.CurrentPrincipal.Identity.Name 而来,即访问当前服务的客户端ID。这个ID是由OAuth服务的拦截器(Interceptor)实现由 AccessToken(String) 转换成服务端用户模型。

在 web.config 中,利用 WCF 对 ASP.NET 的兼容机制,使用 Form 认证:定义了两个用户:john 和 jane
<system.web>
  <compilation debug="true" targetframework="4.0"></compilation>
  <authentication mode="Forms">
    <forms loginurl="Pages/Login.aspx" cookieless="UseUri">
      <credentials passwordformat="Clear">
        <user name="john" password="password"></user>
        <user name="jane" password="password"></user>
      </credentials>
    </forms>
  </authentication>
  <authorization>
    <allow users="*"></allow>
  </authorization>
</system.web>

并修改 Global.asax 的 WebServiceHostFactory,改为 OAuthWebServiceHostFactory 
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

<pre class="brush:php;toolbar:false">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();
        }
    }
}
AccessToken.ashx :交换 RequestToken 返回 AccessToken

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();
        }
    }
}
当然我们还需要提供用户登录和授权的页面:Login.aspx 和 UserAuthorize.aspx Form登录就不累述了, UserAuthorize.aspx 中实现授权的方法如下:
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. 应用

OAuth 学习(2)  自定义OAuth服务端(WCF REST数据访问控制)

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);
        }
    }
}
Callback.ashx
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; }
        }
    }
}



Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn