65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Spring.NET Social 连接社交网络 API

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2013年1月20日

CPOL

8分钟阅读

viewsIcon

23068

downloadIcon

719

Spring.NET Social 帮助您简化与 Facebook 和 Twitter 等软件即服务 (SaaS) 提供商的身份验证 (OAuth) 和 API 绑定。

引言

Spring.NET Social 使添加对框架尚不支持的服务提供商的支持变得容易。

如果您查看现有的客户端项目,例如 TwitterDropboxLinkedInFacebook,您会发现它们的实现方式一致,并且应用了一组定义明确的扩展点。

在本文中,您将学习如何添加对您希望支持的新服务提供商的支持。

流程概述

添加新服务提供商支持的过程包括几个步骤:

  1. 为客户端代码创建一个源项目,例如 Spring.Social.Twitter
  2. 开发或集成到提供商 API 的绑定,例如 ITwitter
  3. 创建一个 IServiceProvider 模型,允许用户授权远程提供商并获取已授权的 API 实例,例如 TwitterServiceProvider

本文的以下部分将通过示例向您介绍每个步骤。

为提供商客户端代码创建源项目

我们建议新社交客户端代码驻留在 Spring.Social.{providerId} 程序集中,其中 {providerId} 是您为添加支持的服务提供商分配的唯一标识符。

在该程序集中,我们建议以下命名空间结构:

命名空间 提供商
Spring.Social.{providerId}.Api 定义 API 绑定的公共接口和类型。
Spring.Social.{providerId}.Api.Impl API 绑定的实现。
Spring.Social.{providerId}.Connect 建立与服务提供商连接所需的类型。

您可以通过查看 Twitter 项目来了解这种推荐结构的实际应用。

在这里,核心服务 API 类型 ITwitter 位于 Api 命名空间中,与其支持的操作类型和数据传输对象类型一起。

该接口的主要实现 TwitterTemplate 位于 Api.Impl 命名空间中(以及已从该视图中排除的其他内部类型)。

最后,Connect 命名空间包含 IServiceProvider 的实现,这些实现使建立与 Twitter 的连接成为可能。

开发提供商 API 绑定

Spring.NET Social 倾向于开发强类型绑定到外部服务提供商 API。
这为 .NET 应用程序提供了一个简单的、面向域的接口来使用该 API。

设计新的 API 绑定

API 开发人员完全控制其 API 绑定的设计和实现。
即便如此,我们还是提供了一些设计指南,以提高整体一致性和质量:

  • 倾向于将 API 绑定接口与其实现分离。
    这在上一节的 Twitter 示例中得到了说明。
    在那里,“Twitter”是核心 API 绑定类型,它在 Spring.Social.Twitter.Api 命名空间中与其他公共类型一起声明。
    TwitterTemplate 是该接口的主要实现,位于 Spring.Social.Twitter.Api.Impl 命名空间中,与其他内部实现类型一起。
  • 倾向于按 RESTful 资源分层组织 API 绑定。
    基于 REST 的 API 通常以分层方式公开对多个资源的访问。
    例如,Twitter 的 API 提供了对“状态时间线”、“搜索”、“列表”、“直接消息”、“好友”、“地理位置”和“用户”的访问。
    ITwitter 接口被分层组织,而不是将所有操作添加到单个扁平的“Twitter”接口中。
public interface ITwitter : IApiBinding
{ 
  IBlockOperations BlockOperations { get; } 
  IDirectMessageOperations DirectMessageOperations { get; } 
  IFriendOperations FriendOperations { get; } 
  IGeoOperations GeoOperations { get; } 
  IListOperations ListOperations { get; } 
  ISearchOperations SearchOperations { get; } 
  ITimelineOperations TimelineOperations { get; } 
  IUserOperations UserOperations { get; } 
  IRestOperations RestOperations { get; } 
} 

例如,IDirectMessageOperations 包含对 Twitter“直接消息”资源的 API 绑定。

public interface IDirectMessageOperations
{ 
  IList<DirectMessage> GetDirectMessagesReceived();
  IList<DirectMessage> GetDirectMessagesReceived(int page, int pageSize);
  IList<DirectMessage> GetDirectMessagesReceived(int page, int pageSize, long sinceId, long maxId);
  IList<DirectMessage> GetDirectMessagesSent();
  IList<DirectMessage> GetDirectMessagesSent(int page, int pageSize); 
  IList<DirectMessage> GetDirectMessagesSent(int page, int pageSize, long sinceId, long maxId)
  DirectMessage GetDirectMessage(long id);
  DirectMessage SendDirectMessage(string toScreenName, string text); 
  DirectMessage SendDirectMessage(long toUserId, string text); 
  void DeleteDirectMessage(long messageId);
} 

实现新的 API 绑定

API 开发人员可以自由地使用他们认为合适的任何 REST/HTTP 客户端来实现其 API 绑定。也就是说,现有的 Spring.NET Social 绑定(如 Twitter)都使用 Spring.NET REST Client FrameworkRestTemplate
RestTemplate 是一个 REST 客户端,可在各种数据交换格式(JSON、XML 等)上提供统一的对象映射接口。

如上一节所述,我们建议将实现类型与公共 API 类型分开。我们还建议将实现细节保持为内部。
API 绑定实现的构造方式将因 API 的授权协议而异。对于使用 OAuth1 保护的 API,构造需要 consumerKeyconsumerSecretaccessTokenaccessTokenSecret

public TwitterTemplate(string consumerKey, string consumerSecret, 
                       string accessToken, string accessTokenSecret) 
{ 
  ... 
} 

对于 OAuth2,只需要 accessToken

public GitHubTemplate(string accessToken) 
{ 
  ... 
} 

每次向 API 服务器发出的请求都需要使用绑定构造过程中提供的授权凭据进行签名。
此签名过程包括在执行每个客户端请求之前,向其添加“Authorization”标头。
对于 OAuth1,此过程非常复杂,用于支持客户端和服务器之间精心设计的请求签名验证算法。
对于 OAuth2,它要简单得多,但仍然因 OAuth2 规范的各种草案而异。

为了封装这种复杂性,对于每种授权协议,Spring Social 都提供了一个基类,您可以从中扩展,以构建一个预配置的 RestTemplate 实例,该实例会为您执行请求签名。

对于 OAuth1

public class TwitterTemplate : AbstractOAuth1ApiBinding 
{
  public TwitterTemplate(string consumerKey, string consumerSecret, 
                         string accessToken, string accessTokenSecret) 
    : base(consumerKey, consumerSecret, accessToken, accessTokenSecret);
  {    
  }
}  

对于 OAuth2

public class GitHubTemplate : AbstractOAuth2ApiBinding 
{
  public GitHubTemplate(string accessToken) 
    : base(accessToken);
  {        
  }
} 

配置好后,您只需实现调用 RestTemplate 并实现各种 API 操作。
现有的 Spring.NET Social 客户端模块都以标准方式调用其 RestTemplate 实例。

public TwitterProfile GetUserProfile() 
{
  return this.RestTemplate.GetForObject<TwitterProfile>("account/verify_credentials.json");
}  

有关完整的实现示例,请参阅基于 Spring.NET Social 的现有扩展的源代码。

测试新的 API 绑定

作为 RestTemplate 组件的一部分,Spring.NET REST Client Framework 包括一个用于单元测试 RestTemplate 代码的框架。
该框架包含一个“MockRestServiceServer”,可用于模拟与远程服务提供商的 API 调用。
这使得能够开发独立、高性能、自动化的单元测试,以验证客户端 API 绑定和对象映射行为。

要使用,请先针对 API 实现使用的 RestTemplate 实例创建 MockRestServiceServer
在此示例中,TwitterTemplate 使用 RestTemplate 来消费 Twitter REST API 资源。

TwitterTemplate twitter = new TwitterTemplate("consumerKey", "consumerSecret", 
                                              "accessToken", "accessTokenSecret");
MockRestServer mockServer = MockRestServiceServer.CreateServer(twitter.RestTemplate);   

然后,对于每个测试用例,记录关于服务器应如何被调用以及应如何响应的期望。

[Test]
public void UpdateStatus() 
{
  HttpHeaders responseHeaders = new HttpHeaders();
  responseHeaders.ContentType = MediaType.APPLICATION_JSON;
    
  mockServer.ExpectNewRequest()
    .AndExpectUri("https://api.twitter.com/1/statuses/update.json")
    .AndExpectMethod(HttpMethod.POST)
    .AndExpectHeader("Content-Type", "application/x-www-form-urlencoded")
    .AndExpectBody("status=Test+Message")
    .AndRespondWith(JsonResource("Status"), responseHeaders);

  Tweet tweet = twitter.UserOperations.UpdateStatus("Test Message");
  Assert.AreEqual(12345, tweet.ID);
  Assert.AreEqual("Test Message", tweet.Text);
} 

在上例中,响应正文是从位于与测试类相同命名空间下的“Status.json”嵌入资源文件中写入的。

private IResource JsonResource(string filename) 
{
  return new AssemblyResource(filename + ".json", typeof(TwitterTemplateTests));
}

文件的内容应镜像远程服务提供商将返回的内容,从而可以完全测试客户端的 JSON 反序列化行为。

{
  "id" : 12345,
  "text" : "Tweet 1",
  ...
}

有关完整的测试示例,请参阅基于 Spring.NET Social 的现有扩展的源代码。

创建 ServiceProvider 模型

如上一节所述,安全 API(如 GitHub 或 Twitter)的客户端绑定需要有效的用户授权凭据才能工作。
此类凭据通常通过让您的应用程序与服务提供商进行授权“舞蹈”或握手来获得。
Spring.NET Social 提供了 IServiceProvider<T> 抽象来处理此“授权舞蹈”。该抽象还充当原生 API (T) 实例的工厂。

由于授权舞蹈是协议特定的,因此存在每个授权协议的 IServiceProvider 特化。
例如,如果您正在连接到基于 OAuth2 的提供商,您将实现 IOAuth2ServiceProvider
完成此操作后,您的实现可用于执行 OAuth2 舞蹈并获取已授权的 API 实例。
以下各节描述了每种 ServiceProvider 类型的实现步骤。

OAuth 2

要实现基于 OAuth2ServiceProvider,请首先创建一个名为 {ProviderId}ServiceProviderAbstractOAuth2ServiceProvider<T> 的子类。
将通用类型 T 参数化为 ServiceProvider API 的绑定。
定义一个接受 clientIdclientSecret 的单一构造函数。
最后,实现 GetApi(string) 来返回一个新的 API 实例。

以 GitHub 和 Facebook 示例作为基于 OAuth2 的服务提供商的示例。

public class GitHubServiceProvider : AbstractOAuth2ServiceProvider<IGitHub>
{
  public GitHubServiceProvider(string clientId, string clientSecret)
    : base(new OAuth2Template(clientId, clientSecret,
      "https://github.com/login/oauth/authorize",
      "https://github.com/login/oauth/access_token"))
  {
  }

  public override IGitHub GetApi(string accessToken)
  {
    return new GitHubTemplate(accessToken);
  }
} 

在构造函数中,您应该调用基类构造函数,并将配置好的、实现 IOAuth2OperationsOAuth2Template 传递上去。
OAuth2Template 将处理与提供商的“OAuth 舞蹈”,并应使用提供的 clientIdclientSecret 以及特定于提供商的 authorizeUrlaccessTokenUrl 进行配置。

一些提供商支持通过与授权 URL 不同的身份验证 URL 进行提供商登录。使用上面的 OAuth2Template 构造函数将假定身份验证 URL 与授权 URL 相同。但是,您可以使用 OAuth2Template 的其他构造函数来指定不同的身份验证 URL。

GetApi(string) 中,您应该构造您的 API 实现,并传递使有权访问受保护资源所需的访问令牌。

OAuth 1

要实现基于 OAuth2ServiceProvider,请首先创建一个名为 {ProviderId}ServiceProviderAbstractOAuth1ServiceProvider<T> 的子类。
将通用类型 T 参数化为 ServiceProvider API 的绑定。
定义一个接受 consumerKeyconsumerSecret 的单一构造函数。
最后,实现 GetApi(string, string) 来返回一个新的 API 实例。

以 Twitter 和 LinkedIn 示例作为基于 OAuth1 的服务提供商的示例。

public class TwitterServiceProvider : AbstractOAuth1ServiceProvider<ITwitter>
{
  public TwitterServiceProvider(string consumerKey, string consumerSecret)
    : base(consumerKey, consumerSecret, new OAuth1Template(consumerKey, consumerSecret,
      "https://api.twitter.com/oauth/request_token",
      "https://api.twitter.com/oauth/authorize",
      "https://api.twitter.com/oauth/authenticate",
      "https://api.twitter.com/oauth/access_token"))
  {
  }

  public override ITwitter GetApi(string accessToken, string secret)
  {
    return new TwitterTemplate(this.ConsumerKey, this.ConsumerSecret, accessToken, secret);
  }
} 

在构造函数中,您应该调用基类构造函数,并将 consumerKeysecret 和实现 IOAuth1Operations 的配置好的 OAuth1Template 传递上去。
OAuth1Template 将处理与提供商的“OAuth 舞蹈”。
它应使用提供的 consumerKeyconsumerSecret 以及特定于提供商的 requestTokenUrlauthorizeUrlauthenticateUrlaccessTokenUrl 进行配置。
authenticateUrl 参数是可选的,如果提供商没有与授权 URL 不同的身份验证 URL,则可以省略。

如您在此处所见,OAuth1Template 使用 Twitter 的身份验证 URL(用于提供商登录)进行构造,该 URL 与其授权 URL 不同。
一些提供商没有用于身份验证和授权的单独 URL。
在这些情况下,您可以使用 OAuth1Template 的其他构造函数,该构造函数不接受身份验证 URL 作为参数。

GetApi(string, string) 中,您应该构造您的 API 实现,并传递使有权访问受保护资源所需的四个令牌。

结论

查看附加的示例,了解使用 Spring.NET Social 连接和使用网络社交 API 的便捷性。

© . All rights reserved.