3

I am developing with Spring Social and Thymeleaf from the quick start example, but I realised that it only supports one Facebook object per controller. This means the sample can't provide support for multiple users and I am guessing it has to do with the @Scope of the variable. Its runs in a Spring boot container and I wonder how I can configure this so that each session has its own Facebook object.

F.O.O
  • 4,730
  • 4
  • 24
  • 34
  • 1
    I think you get one `Facebook` per request with the default auto configuration (just inject it into your controller and it will already be a request-scoped proxy). What makes you think it isn't working? – Dave Syer Nov 11 '14 at 12:36
  • 2
    Because when I check with another browser it assumes I am the same user. – F.O.O Nov 11 '14 at 12:46
  • Define another browser? A new tab or browser window opened with CTRL+N isn't a new browser. Also starting multiple instances of Chrome or Firefox will lead to session attachment. – M. Deinum Nov 11 '14 at 12:56
  • That's at application level meaning I tried an entirely different browser, and I confirmed a new session was created by printing the session id. But Facebook object stays authorized across sessions – F.O.O Nov 11 '14 at 13:04
  • You did use the auto-configuration support for Spring Social Facebook? Or did you configure it yourself? – M. Deinum Nov 11 '14 at 13:05

2 Answers2

2

As you suggested, the Facebook object should be configured with request scope. If you're using the configuration support and/or Spring Boot, then it will be request scoped. Therefore, even though the controller is injected once with a Facebook instance, that instance is really a proxy that will delegate to a real FacebookTemplate instance that is created at request time for the authenticated user.

I can only assume that you're referring to the getting started guide example at http://spring.io/guides/gs/accessing-facebook/. In that case, it's using the most simple Spring Boot autoconfiguration possible for Spring Social, which includes a basic (yet not intended for production) implementation of UserIdSource which always returns "anonymous" as the user ID. Therefore, after you create the first Facebook connection, the second browser tries to find a connection for "anonymous", finds it, and gives you an authorized Facebook object.

This may seem peculiar, but it is an example app intended to get you started...and it does that. All you need to do to get a real UserIdSource is to add Spring Security to the project. That will tell Spring Social autoconfiguration to configure a UserIdSource that fetches the current user ID from the security context. This reflects a more real-world use of Spring Social, albeit obviously more involved and beyond the scope of the getting started guide.

But you can look at https://github.com/spring-projects/spring-social-samples/tree/master/spring-social-showcase-boot for a more complete example of Spring Social within Spring Boot.

Craig Walls
  • 2,080
  • 1
  • 12
  • 13
  • http://spring.io/guides/gs/accessing-facebook/ link needs include your advise about multiple users can't login – bora.oren Feb 28 '15 at 19:49
2

Spring Boot autoconfigures a lot of things behind the scenes. It does autoconfigure the Facebook, LinkedIn and Twitter properties and sets up the connection factories for social providers.

However, the implementation of UserIdSource always returns “anonymous” as the user ID. Once the first Facebook connection is established the second browser will try to find a connection for “anonymous” which it finds and gives you an authorised Facebook object.

@Configuration
@EnableSocial
@ConditionalOnWebApplication
@ConditionalOnMissingClass("org.springframework.security.core.context.SecurityContextHolder")
protected static class AnonymousUserIdSourceConfig extends SocialConfigurerAdapter {

    @Override
    public UserIdSource getUserIdSource() {
        return new UserIdSource() {
            @Override
            public String getUserId() {
                return "anonymous";
            }
        };
    }
}

Solution

The solution is to override the “anonymous” as the UserId for each new user/session. So for each session, we can simply return a SessionID, however, it may not be unique enough to identify users, especially if it’s being cached or stored somewhere in a connection database.

@Override
public String getUserId() {
    RequestAttributes request = RequestContextHolder.currentRequestAttributes();
    String uuid = (String) request.getAttribute("_socialUserUUID", RequestAttributes.SCOPE_SESSION);
    if (uuid == null) {
        uuid = UUID.randomUUID().toString();
        request.setAttribute("_socialUserUUID", uuid, RequestAttributes.SCOPE_SESSION);
    }
    return uuid;
}

The solution for above problem has been talked about in detail over here

Mahozad
  • 18,032
  • 13
  • 118
  • 133
Abhishek Galoda
  • 2,753
  • 24
  • 38