In this blog, I’m going to cover the scenario where you have a requirement to display a user’s Facebook or other Software as a Service (SaaS) provider data on one or two pages of your application. The idea here is to try to demonstrate the smallest and simplest thing you can to to add Spring Social to an application that requires your user to log in to Facebook or other SaaS provider.
Creating the App
To create the application, the first step is to create a basic Spring MVC Project using the template section of the SpringSource Toolkit Dashboard. This provides a webapp that’ll get you started.
The next step is to set up the by adding the following dependencies:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-crypto</artifactId>
<version>${org.springframework.security.crypto-version}</version>
</dependency>
<!-- Spring Social -->
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-core</artifactId>
<version>${spring-social.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-web</artifactId>
<version>${spring-social.version}</version>
</dependency>
<!-- Facebook API -->
<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-facebook</artifactId>
<version>${org.springframework.social-facebook-version}</version>
</dependency>
<!-- JdbcUserConfiguration -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.3.159</version>
</dependency>
<!-- CGLIB, only required and used for @Configuration usage: could be removed in future release of Spring -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.2</version>
</dependency>…obviously you’ll also need to add the following to the section of the file:
<spring-social.version>1.0.2.RELEASE</spring-social.version> <org.springframework.social-facebook-version>1.0.1.RELEASE</org.springframework.social-facebook-version> <org.springframework.security.crypto-version>3.1.0.RELEASE</org.springframework.security.crypto-version>
You’ll notice that I’ve added a specific pom entry for : this is because I’m using Spring 3.0.6. In Spring 3.1.x, this has become part of the core libraries.
The only other point to note is that there is also a dependency on and . This is because Spring’s default implementation: uses them and hence they’re required even though this app doesn’t persist anything to a database (so far as I can tell).
The Classes
The social coding functionality consists of four classes (and one of those I’ve pinched from Keith Donald’s Spring Social Quick Start Sample code):
- FacebookPostsController
- SocialContext
- FacebookConfig
- UserCookieGenerator
is the business end of the application responsible for getting hold of the user’s Facebook data and pushing it into the model ready for display.
@Controller
public class FacebookPostsController {
private static final Logger logger = LoggerFactory.getLogger(FacebookPostsController.class);
private final SocialContext socialContext;
@Autowired
public FacebookPostsController(SocialContext socialContext) {
this.socialContext = socialContext;
}
@RequestMapping(value = 'posts', method = RequestMethod.GET)
public String showPostsForUser(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {
String nextView;
if (socialContext.isSignedIn(request, response)) {
List<Post> posts = retrievePosts();
model.addAttribute('posts', posts);
nextView = 'show-posts';
} else {
nextView = 'signin';
}
return nextView;
}
private List<Post> retrievePosts() {
Facebook facebook = socialContext.getFacebook();
FeedOperations feedOps = facebook.feedOperations();
List<Post> posts = feedOps.getHomeFeed();
logger.info('Retrieved ' + posts.size() + ' posts from the Facebook authenticated user');
return posts;
}
}As you can see, from a high-level viewpoint the logic of what we’re trying to achieve is pretty simple:
IF user is signed in THEN read Facebook data, display Facebook data ELSE ask user to sign in when user has signed in, go back to the beginning END IF
The delegates the task of handling the sign in logic to the class. You can probably guess that I got the idea for this class from Spring’s really useful . The idea here is that there is one class that’s responsible for gluing your application to Spring Social.
public class SocialContext implements ConnectionSignUp, SignInAdapter {
/**
* Use a random number generator to generate IDs to avoid cookie clashes
* between server restarts
*/
private static Random rand;
/**
* Manage cookies - Use cookies to remember state between calls to the
* server(s)
*/
private final UserCookieGenerator userCookieGenerator;
/** Store the user id between calls to the server */
private static final ThreadLocal<String> currentUser = new ThreadLocal<String>();
private final UsersConnectionRepository connectionRepository;
private final Facebook facebook;
public SocialContext(UsersConnectionRepository connectionRepository, UserCookieGenerator userCookieGenerator,
Facebook facebook) {
this.connectionRepository = connectionRepository;
this.userCookieGenerator = userCookieGenerator;
this.facebook = facebook;
rand = new Random(Calendar.getInstance().getTimeInMillis());
}
@Override
public String signIn(String userId, Connection<?> connection, NativeWebRequest request) {
userCookieGenerator.addCookie(userId, request.getNativeResponse(HttpServletResponse.class));
return null;
}
@Override
public String execute(Connection<?> connection) {
return Long.toString(rand.nextLong());
}
public boolean isSignedIn(HttpServletRequest request, HttpServletResponse response) {
boolean retVal = false;
String userId = userCookieGenerator.readCookieValue(request);
if (isValidId(userId)) {
if (isConnectedFacebookUser(userId)) {
retVal = true;
} else {
userCookieGenerator.removeCookie(response);
}
}
currentUser.set(userId);
return retVal;
}
private boolean isValidId(String id) {
return isNotNull(id) && (id.length() > 0);
}
private boolean isNotNull(Object obj) {
return obj != null;
}
private boolean isConnectedFacebookUser(String userId) {
ConnectionRepository connectionRepo = connectionRepository.createConnectionRepository(userId);
Connection<Facebook> facebookConnection = connectionRepo.findPrimaryConnection(Facebook.class);
return facebookConnection != null;
}
public String getUserId() {
return currentUser.get();
}
public Facebook getFacebook() {
return facebook;
}
}implements Spring Social’s and interfaces. It contains three methods , , . is called by the class to implement the logic above, whilst and are called by Spring Social.
From my previous blogs you’ll remember that OAuth requires lots of trips between the browser, your app and the SaaS provider. In making these trips the application needs to save the state of several OAuth arguments such as: client_id, redirect_uri and others. Spring Social hides all this complexity from your application by mapping the state of the OAuth conversation to one variable that your webapp controls. This is the ; however, don’t think of think of this as a user name because it’s never seen by the user, it’s just a unique identifier that links a number of HTTP requests to an SaaS provider connection (such as Facebook) in the Spring Social core.
Because of its simplicity, I’ve followed Keith Donald’s idea of using cookies to pass the user id between the browser and the server in order to maintain state. I’ve also borrowed his class from the Spring Social Quick Start to help me along.
The method uses to figure out if the object contains a cookie that contains a valid user id. If it does then it also figures out if Spring Social’s contains a linked to the same user id. If both of these tests return then the application will request and display the user’s Facebook data. If one of the two tests returns false, then the user will be asked to sign in.
has been written specifically for this sample and contains enough functionality to demonstrate what I’m talking about in this blog. This means that it’s currently a little rough and ready, though it could be improved to cover connections to any / many providers and then reused in different applications.
The final class to mention is , which is loosely based upon the Spring Social sample code. There are two main differences between this code and the sample code with the first of these being that the class implements the interface. This is so that the variable can be injected into the and in turn the can be injected into the as its implementation. The second difference is that I’m implementing a method to provide a correctly configured object to be used by Spring Social to sign in to Facebook. The only change to the default I’ve made here is to set the ’s property to “ ”. This is the url of the page that will contain the users Facebook data and will be called once the user sign in is complete.
@Configuration
public class FacebookConfig implements InitializingBean {
private static final Logger logger = LoggerFactory.getLogger(FacebookConfig.class);
private static final String appId = '439291719425239';
private static final String appSecret = '65646c3846ab46f0b44d73bb26087f06';
private SocialContext socialContext;
private UsersConnectionRepository usersConnectionRepositiory;
@Inject
private DataSource dataSource;
/**
* Point to note: the name of the bean is either the name of the method
* 'socialContext' or can be set by an attribute
*
* @Bean(name='myBean')
*/
@Bean
public SocialContext socialContext() {
return socialContext;
}
@Bean
public ConnectionFactoryLocator connectionFactoryLocator() {
logger.info('getting connectionFactoryLocator');
ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
registry.addConnectionFactory(new FacebookConnectionFactory(appId, appSecret));
return registry;
}
/**
* Singleton data access object providing access to connections across all
* users.
*/
@Bean
public UsersConnectionRepository usersConnectionRepository() {
return usersConnectionRepositiory;
}
/**
* Request-scoped data access object providing access to the current user's
* connections.
*/
@Bean
@Scope(value = 'request', proxyMode = ScopedProxyMode.INTERFACES)
public ConnectionRepository connectionRepository() {
String userId = socialContext.getUserId();
logger.info('Createung ConnectionRepository for user: ' + userId);
return usersConnectionRepository().createConnectionRepository(userId);
}
/**
* A proxy to a request-scoped object representing the current user's
* primary Facebook account.
*
* @throws NotConnectedException
* if the user is not connected to facebook.
*/
@Bean
@Scope(value = 'request', proxyMode = ScopedProxyMode.INTERFACES)
public Facebook facebook() {
return connectionRepository().getPrimaryConnection(Facebook.class).getApi();
}
/**
* Create the ProviderSignInController that handles the OAuth2 stuff and
* tell it to redirect back to /posts once sign in has completed
*/
@Bean
public ProviderSignInController providerSignInController() {
ProviderSignInController providerSigninController = new ProviderSignInController(connectionFactoryLocator(),
usersConnectionRepository(), socialContext);
providerSigninController.setPostSignInUrl('/posts');
return providerSigninController;
}
@Override
public void afterPropertiesSet() throws Exception {
JdbcUsersConnectionRepository usersConnectionRepositiory = new JdbcUsersConnectionRepository(dataSource,
connectionFactoryLocator(), Encryptors.noOpText());
socialContext = new SocialContext(usersConnectionRepositiory, new UserCookieGenerator(), facebook());
usersConnectionRepositiory.setConnectionSignUp(socialContext);
this.usersConnectionRepositiory = usersConnectionRepositiory;
}
}Application Flow
If you run this application 2 you’re first presented with the home screen containing a simple link inviting you to display your posts. The first time you click on this link, you’re re-directed to the page. Pressing the ‘sign in’ button tells the to contact Facebook. Once authentication is complete, then the directs the app back to the page and this time it displays the Facebook data.
Configuration
For completeness, I thought that I should mention the XML config, although there’s not much of it because I’m using the Spring annotation on the class. I have imported “ ” from the Spring Social so that works and added
<context:component-scan base-package='com.captaindebug.social' />
…for autowiring.
Summary
Although this sample app is based upon connecting your app to your user’s Facebook data, it can be easily modified to use any of the Spring Social client modules. If you like a challenge, try implementing Sina-Weibo where everything’s in Chinese – it’s a challenge, but Google Translate comes in really useful.
1 Spring Social and Other OAuth Blogs:
- Getting Started with Spring Social
- Facebook and Twitter: Behind the Scenes
- The OAuth Administration Steps
- OAuth 2.0 Webapp Flow Overview
2 The code is available on Github at: https://github.com/roghughe/captaindebug.git
Reference: Getting Started with Spring Social – Part 2 from our JCG partner Roger Hughes at the Captain Debug’s Blog blog.
Thank you!
We will contact you soon.
Roger HughesJuly 20th, 2012Last Updated: October 22nd, 2012

This site uses Akismet to reduce spam. Learn how your comment data is processed.
thanks for ur nice tutorial
btw hope it is not your real secret key :P
Good tutorial, but you dont explain anything about the view of this MVC arquitecture. The tutorial looks incomplete for me.