Home > Database > Mysql Tutorial > body text

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

WBOY
Release: 2016-06-07 15:27:37
Original
1307 people have browsed it

上篇了解了如何调用 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>
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login

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



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>
Copy after login
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>
Copy after login
上面的 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>
Copy after login

并修改 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)));
    }
}
Copy after login

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

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

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);
        }
    }
}
Copy after login
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; }
        }
    }
}
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Copy after login
Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template