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.
2 回答
正如您所建议的,Facebook 对象应配置为请求范围。如果您正在使用配置支持和/或 Spring Boot,那么它将是请求范围的。因此,即使控制器被注入一次 Facebook 实例,该实例实际上是一个代理,它将委托给一个真实的 FacebookTemplate 实例,该实例是在请求时为经过身份验证的用户创建的。
我只能假设您指的是http://spring.io/guides/gs/accessing-facebook/上的入门指南示例。在这种情况下,它为 Spring Social 使用了最简单的 Spring Boot 自动配置,其中包括 UserIdSource 的基本(但不用于生产)实现,它始终返回“匿名”作为用户 ID。因此,在您创建第一个 Facebook 连接后,第二个浏览器会尝试为“匿名”找到一个连接,找到它,并为您提供一个授权的 Facebook 对象。
这可能看起来很奇怪,但它是一个旨在让您入门的示例应用程序......它确实做到了。要获得真正的 UserIdSource,您需要做的就是将 Spring Security 添加到项目中。这将告诉 Spring Social 自动配置配置一个从安全上下文中获取当前用户 ID 的 UserIdSource。这反映了对 Spring Social 的更真实的使用,尽管显然更多涉及并且超出了入门指南的范围。
但是您可以查看https://github.com/spring-projects/spring-social-samples/tree/master/spring-social-showcase-boot以获得 Spring Boot 中更完整的 Spring Social 示例。
Spring Boot 在幕后自动配置了很多东西。它会自动配置 Facebook、LinkedIn 和 Twitter 属性,并为社交提供者设置连接工厂。
但是,UserIdSource 的实现总是返回“匿名”作为用户 ID。一旦建立了第一个 Facebook 连接,第二个浏览器将尝试为“匿名”找到一个连接,它找到并为您提供一个授权的 Facebook 对象。
@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";
}
};
}
}
解决方案
解决方案是将“匿名”覆盖为每个新用户/会话的 UserId。因此,对于每个会话,我们可以简单地返回一个 SessionID,但是,它可能不够唯一,无法识别用户,尤其是当它被缓存或存储在连接数据库中的某个位置时。
@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;
}