Get ahead
VMware offers training and certification to turbo-charge your progress.
Learn moreIn my previous post, I introduced you to Spring Social's Java bindings to popular Software-as-a-Service (SaaS) APIs such as Twitter, Facebook, LinkedIn, and TripIt. In addition to providing simple, strongly-typed Java methods for common API operations, these bindings ensure each HTTP request includes the credentials required to authorize your application to invoke the API on behalf of a user.
What my first post did not address was: how do we manage the credentials required to invoke service APIs on behalf of users? I'm pleased to say that we now have answers to that question.
Earlier this week, we announced the release of the second milestone of the Spring Social project. The most significant new feature in Spring Social 1.0.0.M2 is the introduction of a Service Provider "Connect" framework. Today I want to introduce you to this framework and show you how to use it to manage "connections" to SaaS providers.
The examples in this article are from the Spring Social Showcase. To follow along, clone the repository and follow the README to build and deploy the sample app.
With the M2 release, Spring Social has been split into several modules:
Depending on your needs, you won't necessarily need all of these modules. At a minimum, you'll need the core module. You can add this to a Maven-built project with the following entry:
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-core</artifactId>
<version>1.0.0.M2</version>
</dependency>
In the likely case that you'll be using Spring Social in a web application, you'll also need the web module:
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-web</artifactId>
<version>1.0.0.M2</version>
</dependency>
Then, you'll need to add one or more of the provider modules. In our examples, we'll be talking about adding Twitter connectivity to an application, so we'll need the twitter module:
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-twitter</artifactId>
<version>1.0.0.M2</version>
</dependency>
Since we're building off of a milestone release of Spring Social, we're going to need to add Spring's milestone repository to the pom.xml file:
<repository>
<id>org.springframework.maven.milestone</id>
<name>Spring Maven Milestone Repository</name>
<url>http://maven.springframework.org/milestone</url>
<snapshots><enabled>false</enabled></snapshots>
</repository>
Note that although Spring Social 1.0.0.M2 has a compile-time dependency on Spring Framework 3.1, Spring Social also works fine with Spring Framework 3.0.x.
With the dependencies addressed in our build, we're ready to add Twitter connectivity to the application.
To help understand what Spring Social's Service Provider "Connect" Framework brings to the table, let's take a quick tour through the showcase application.
After signing into the showcase sample, the first thing you'll see are a list of the service providers that the showcase supports connectivity with: Twitter, Facebook, and TripIt. They should all show that your account is not yet connected to any of them.
If you click on the Twitter link, you'll be redirected to a connection status page and be given the opportunity to "Connect with Twitter". You'll also see a checkbox that, if checked, will post a tweet about Spring Social Showcase after connecting to Twitter.
After clicking the "Connect with Twitter" button (I'll let you decide whether or not to check the "Post tweet..." checkbox), you'll be redirected to Twitter's authorization page, which should look something like this:
The username and password fields won't be shown if you're already signed into Twitter. But in either case, you'll be given an opportunity to deny or allow the showcase example the right to access and update your data on Twitter. When you click on the "Allow" button to grant permission, Twitter will redirect back to the showcase application and a connection will be created between the showcase account and your Twitter profile. You'll be shown a connection status page, this time indicating that a connection exists.
At this point, you may choose to disconnect from Twitter if you'd like. But for now, return to the home page and you'll see that you are now connected to Twitter.
If you click on the "Twitter" link, with a connection available, you'll be taken to the Twitter Showcase page which displays, among other things, your profile image, Twitter display name, and Twitter screen name. You may also choose to connect another Twitter account from here (you may connect multiple provider accounts to a single application account), disconnect from Twitter, or post a tweet.
When you first clicked on the "Twitter" link in the showcase sample, you were shown a status connection page for Twitter. This page is served by Spring Social's ConnectController
. ConnectController
is a Spring MVC controller that handles the authorization process. In the case of Twitter, that's an OAuth 1 authorization flow. For OAuth 1, ConnectController
supports the following flow:
ConnectController
also supports OAuth 2's authorization flow. When authorizing against an OAuth 2 based provider like Facebook, ConnectController
's flow is slightly different:
ConnectController
can be configured in a Spring MVC application as simple as adding the following <bean>
element:
<bean class="org.springframework.social.web.connect.ConnectController">
<constructor-arg value="${application.url}" />
</bean>
If you look at how ConnectController
is configured in the showcase sample, however, you'll see that it has an interceptors
property injected with a list of interceptor beans. Connect interceptors let you inject custom functionality into the connection flow. One of those interceptors, TweetAfterConnectInterceptor
, is responsible for posting a tweet after you connect with Twitter. (See the reference documentation for more information on connection interceptors.)
When a request goes to ConnectController
, it works with a service provider class to handle the behind-the-scenes interaction with the service. In the case of Twitter, that provider class is TwitterServiceProvider
and is configured in Spring like this:
<bean class="org.springframework.social.twitter.connect.TwitterServiceProvider">
<constructor-arg value="${twitter.appId}" />
<constructor-arg value="${twitter.appSecret}" />
<constructor-arg ref="connectionRepository" />
</bean>
TwitterServiceProvider
, like all of Spring's service provider implementations, is constructed with the following arguments:
You obtain the application's consumer key and secret when you register the application with the service provider. To register an application with Twitter go to https://dev.twitter.com/apps/new and fill out the form. When you're done, Twitter will respond with a page showing details about your application, including the consumer key and consumer secret.
In this case, the application's Twitter application ID and secret are expressed as placeholder variables to be resolved by a property placeholder configurer. It's recommended that you externalize these details, since you'll likely have a different ID/secret pair for your production deployment than you would for testing and development environments.
Each of Spring's service provider classes has a provider ID (returned from its getId()
method and different than its Spring bean ID). ConnectController
will use that ID, as specified in the URL path, to choose the service provider it will work with when creating connections. For TwitterServiceProvider
, the provider ID is "twitter". Mapping this ID to ConnectController
's request mappings, we get the following flow:
Once a connection has been established, it's important to store it away for future use so that you won't have to repeatedly ask your users to reauthorize your application. Therefore, TwitterServiceProvider
relies on a connection repository to persist the connection information. Spring Social provides JdbcConnectionRepository
, which persists connection details in a relational database. The JdbcConnectionRepository
bean is configured like this:
<bean id="connectionRepository" class="org.springframework.social.connect.jdbc.JdbcConnectionRepository">
<constructor-arg ref="dataSource" />
<constructor-arg ref="textEncryptor" />
</bean>
The JdbcConnectionRepository
depends on a data source through which it will access the database as well as an instance of Spring Security 3.1's TextEncryptor
interface. It uses the text encryptor to encrypt the connection credentials (e.g., access token and secret) when storing them in the database. As a sample application, Spring Security's encryption needs are rather light, so it's wired with a no-op text encryptor:
<bean id="textEncryptor" class="org.springframework.security.crypto.encrypt.Encryptors"
factory-method="noOpText" />
(For production-level encryption, consider one of the other encryptors offered by Spring Security's Encryptors static factory class.)
When you first signed into the Spring Social Showcase, it displayed a list of service providers and indicated that you were not connected with any of them. After going through the connection process with Twitter and returning to that page, it showed that a connection had been established.
The showcase application's HomeController
determines the connection status with each of the providers, by calling their isConnected()
method:
for (ServiceProvider<?> serviceProvider : serviceProviders) {
boolean connected = serviceProvider.isConnected(currentUser.getName());
model.addAttribute(serviceProvider.getId() + "_status", connected ? "Yes" : "No");
}
The isConnected()
method will return true if there is one or more connections between the given account and the service provider.
You may also ask the provider for a list of connections by calling its getConnections()
method:
List<ServiceProviderConnection<TwitterApi>> connections = twitterProvider.getConnections(currentUser.getName());
From any one of those connections, you may retrieve the service API. For example, to get an instance of TwitterApi
from the first connection:
TwitterApi twitter = connections.get(0).getServiceApi();
With that TwitterApi
object you may interact with Twitter, fetching timeline entries, posting tweets, or any of the other operations defined in the TwitterApi
interface.
A key thing to notice here is that at no point is it necessary for application code to deal directly with access tokens and secrets in order to interact with the service. The service provider framework deals with those details under the covers.
Spring Social 1.0.0.M2 brings a service provider framework to the table that greatly simplifies an application's role in obtaining authorization to access a service on behalf of a user and connecting the user's local application account to their account on the provider. Adding connection capabilities to a Spring application involves configuring a service provider as a bean in the Spring application context and Spring Social's ConnectController
to handle the authorization process. The reference documentation has more information on using Spring Social's service provider framework.
Although Spring Social 1.0.0.M2 only offers service provider implementations for 6 providers (Facebook, Twitter, LinkedIn, TripIt, GitHub, and Gowalla), the framework is easily extensible. In a followup article, I'll show you what goes into writing a custom service provider implementation, enabling you to use Spring Social's connection support for any provider you need to connect to.
As always, we are very interested in hearing your feedback. We encourage you to collaborate with us in the forum or by submitting enhancement requests in issue tracking.