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

WBOY
Lepaskan: 2016-06-07 15:27:37
asal
1302 orang telah melayarinya

上篇了解了如何调用 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>
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

拦截器(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; }
}
Salin selepas log masuk



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>
Salin selepas log masuk
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>
Salin selepas log masuk
上面的 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>
Salin selepas log masuk

并修改 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)));
    }
}
Salin selepas log masuk

作为一个基本的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();
        }
    }
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
AccessToken.ashx :交换 RequestToken 返回 AccessToken
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

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();
        }
    }
}
Salin selepas log masuk
当然我们还需要提供用户登录和授权的页面: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);
}
Salin selepas log masuk

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);
        }
    }
}
Salin selepas log masuk
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; }
        }
    }
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
sumber:php.cn
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan