5 date: "2016-01-25T13:43:26+00:00"
6 guid: http://juplo.de/?p=613
18 title: 'Develop a Facebook-App with Spring-Social – Part III: Implementing a UserIdSource'
19 url: /develop-a-facebook-app-with-spring-social-part-03-implementing-a-user-id-source/
22 In this series of Mini-How-Tow's I will describe how to develop a facebook app with the help of [Spring-Social](http://projects.spring.io/spring-social/ "Learn more about Spring-Social")
24 In [the last part of this series](/develop-a-facebook-app-with-spring-social-part-02-how-spring-social-works/ "Read part 2 of this series, to understand, why the first example cannot work as a real app!"), I explained, why the nice little example from the Getting-Started-Guide " [Accessing Facebook Data](http://spring.io/guides/gs/accessing-facebook/ "Read the official Getting-Started-Guide")" cannot function as a real facebook-app.
26 In this part, we will try to solve that problem, by implementing a `UserIdSource`, that tells Spring Social, which user it should connect to the API.
28 ## The Source is With You
30 You can find the source-code on [/git/examples/facebook-app/](/git/examples/facebook-app/ "Link for cloning")
31 and [browse it via gitweb](/gitweb/?p=examples/facebook-app;a=summary "Browse the source-code now").
32 Check out `part-03` to get the source for this part of the series.
34 ## Introducing `UserIdSource`
36 The `UserIdSource` is used by Spring Social to ask us, which user it should connect with the social net.
37 Clearly, to answer that question, we must remeber, which user we are currently interested in!
39 ## Remember Your Visitors
41 In order to remember the current user, we implement a simple mechanism, that stores the ID of the current user in a cookie and retrieves it from there for subsequent calls.
42 This concept was borrowed — again — from [the official code examples](https://github.com/spring-projects/spring-social-samples "Clone the official code examples from GitHub").
43 You can find it for example in the [quickstart-example](https://github.com/spring-projects/spring-social-samples/tree/master/spring-social-quickstart "Clone the quickstart-example from GitHub").
45 **It is crucial to stress, that this concept is inherently insecure and should never be used in a production-environment.**
46 As the ID of the user is stored in a cookie, an attacker could simply take over control by sending the ID of any currently connected user, he is interested in.
48 The concept is implemented here only for educational purposes.
49 It will be replaced by Spring Security later on.
50 But for the beginning, it is easier to understand, how Spring Social works, if we implement a simple version of the mechanism ourself.
52 ## Pluging in Our New Memory
54 The internals of our implementation are not of interest.
55 You may explore them by yourself.
56 In short, it stores the ID of each new user in a cookie.
57 By inspecting that cookie, it can restore the ID of the user on subsequent calls.
59 What is from interest here is, how we can plug in this simple example-mechanism in Spring Social.
61 Mainly, there are two hooks to do that, that means: two interfaces, we have to implement:
64 Spring Social uses an instance of this interface to ask us, which users authorizations it should load from its persistent store of user/connection-mappings.
65 We already have seen an implementation of that one in [the last part of our series](develop-a-facebook-app-with-spring-social-part-02-how-spring-social-works/#AnonymousUserIdSource "Jump back to the last part of our series").
67 1. **ConnectionSignUp**:
68 Spring Social uses an instance of this interface, to ask us about the name it should use for a new user during sign-up.
72 The implementation of `ConnectionSignUp` simply uses the ID, that is provided by the social network.
73 Since we are only signing in users from Facebook, these ID's are guaranteed to be unique.
76 public class ProviderUserIdConnectionSignUp implements ConnectionSignUp
79 public String execute(Connection connection)
81 return connection.getKey().getProviderUserId();
87 The implementation of `UserIdSource` retrieves the ID, that was stored in the `SecurityContext` (our simple implementation — not to be confused with the class from Spring Security).
88 If no user is stored in the `SecurityContext`, it falls back to the old behavior and returns the fix id `anonymous`.
91 public class SecurityContextUserIdSource implements UserIdSource
93 private final static Logger LOG =
94 LoggerFactory.getLogger(SecurityContextUserIdSource.class);
97 public String getUserId()
99 String user = SecurityContext.getCurrentUser();
102 LOG.debug("found user \"{}\" in the security-context", user);
106 LOG.info("found no user in the security-context, using \"anonymous\"");
117 To replace the `AnonymousUserIdSource` by our new implementation, we simply instantiate that instead of the old one in our configuration-class `SocialConfig`:
121 public UserIdSource getUserIdSource()
123 return new SecurityContextUserIdSource();
128 There are several ways to plug in the `ConnectionSignUp`.
129 I decided, to plug it into the instance of `InMemoryUsersConnectionRepository`, that our configuration uses, because this way, the user will be signed up automatically on sign in, if it is not known to the application:
133 public UsersConnectionRepository getUsersConnectionRepository(
134 ConnectionFactoryLocator connectionFactoryLocator
137 InMemoryUsersConnectionRepository repository =
138 new InMemoryUsersConnectionRepository(connectionFactoryLocator);
139 repository.setConnectionSignUp(new ProviderUserIdConnectionSignUp());
145 This makes sense, because our facebook-app uses Facebook, to sign in its users, and, because of that, does not have its own user-model.
146 It can just reuse the user-data provided by facebook.
148 The other approach would be, to officially sign up users, that are not known to the app.
149 This is achieved, by redirecting to a special URL, if a sign-in fails, because the user is unknown.
150 These URL then presents a formular for sign-up, which can be prepopulated with the user-data provided by the social network.
151 You can read more about this approach in the [official documentation](http://docs.spring.io/spring-social/docs/1.1.4.RELEASE/reference/htmlsingle/#signing-up-after-a-failed-sign-in "Read more on signing up after a faild sign-in in the official documentation").
155 So, let us see, if our refinement works. Run the following command and log into your app with at least two different users:
158 git clone /git/examples/facebook-app/
161 mvn spring-boot:run \
162 -Dfacebook.app.id=YOUR_ID \
163 -Dfacebook.app.secret=YOUR_SECRET \
164 -Dlogging.level.de.juplo.yourshouter=debug
168 (The last part of the command turns on the `DEBUG` logging-level, to see in detail, what is going on.
170 ## But What The \*\#! Is Going On There?!?
172 **Unfortunately, our application shows exactly the same behavior as, before our last refinement.**
175 If you run the application in a debugger and put a breakpoint in our implementation of `ConnectionSignUp`, you will see, that this code is never called.
176 But it is plugged in in the right place and should be called, if _a new user signs in_!
178 The solution is, that we are using the wrong mechanism.
179 We are still using the `ConnectController` which was configured in the simple example, we extended.
180 But this controller is meant to connect a _known user_ to one or more _new social services_.
181 This controller assumes, that the user is already signed in to the application and can be retrieved via the configured `UserIdSource`.
183 **To sign in a user to our application, we have to use the `ProviderSignInController` instead!**
187 In [the next part](/develop-a-facebook-app-with-spring-social-part-04-signing-in-users "Jump to the next part of this series and read on...") of this series, I will show you, how to change the configuration, so that the `ProviderSignInController` is used to sign in (and automatically sign up) users, that were authenticated through the Graph-API from Facebook.