【发布时间】:2018-11-09 22:21:41
【问题描述】:
规格
可以通过 userDetailsService 调用 loadUserFromUsername() 的过滤器,以便从自定义 UserDetails 实例中检索租户数据库详细信息。
问题
无论过滤器优先级设置为什么,此自定义过滤器在安全过滤器之前运行,因此弹簧安全上下文未填充或为空。我已确认当我从控制器访问主体对象时会填充此上下文。
尝试
我已将 application.properties 中的 spring 安全顺序设置为 5,并且在注册此过滤器时,我使用了越来越小的值,但它总是在之前运行。 我知道通用过滤器 bean 应该允许我将其设置为在安全配置之后,但我不知道如何将配置和过滤器移动到一个通用过滤器 bean 中。
TenantFilter.java
@Component
public class TenantFilter implements Filter {
@Autowired
private TenantStore tenantStore;
@Autowired
private UserService userService;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
User user = null;
try {
user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
} catch (UsernameNotFoundException ignored) {}
String tenantId = user != null ? user.getSchool().getCode() : "";
try {
this.tenantStore.setTenantId(tenantId);
chain.doFilter(servletRequest, servletResponse);
} finally {
// Otherwise when a previously used container thread is used, it will have the old tenant id set and
// if for some reason this filter is skipped, tenantStore will hold an unreliable value
this.tenantStore.clear();
}
}
@Override
public void destroy() {
}
}
TenantFilterConfig.java
@Configuration
public class TenantFilterConfig {
@Bean
public Filter tenantFilter() {
return new TenantFilter();
}
@Bean
public FilterRegistrationBean tenantFilterRegistration() {
FilterRegistrationBean result = new FilterRegistrationBean();
result.setFilter(this.tenantFilter());
result.setUrlPatterns(Lists.newArrayList("/*"));
result.setName("Tenant Store Filter");
result.setOrder(Ordered.LOWEST_PRECEDENCE-1);
return result;
}
@Bean(destroyMethod = "destroy")
public ThreadLocalTargetSource threadLocalTenantStore() {
ThreadLocalTargetSource result = new ThreadLocalTargetSource();
result.setTargetBeanName("tenantStore");
return result;
}
@Primary
@Bean(name = "proxiedThreadLocalTargetSource")
public ProxyFactoryBean proxiedThreadLocalTargetSource(ThreadLocalTargetSource threadLocalTargetSource) {
ProxyFactoryBean result = new ProxyFactoryBean();
result.setTargetSource(threadLocalTargetSource);
return result;
}
@Bean(name = "tenantStore")
@Scope(scopeName = "prototype")
public TenantStore tenantStore() {
return new TenantStore();
}
}
【问题讨论】:
-
你的用户数据是什么?从委托人那里获取数据后?
-
@fabionoth User 扩展了 UserDetails,我的 loadUserFromUserName 返回了一个 User,所以我应该能够将它转换为 User 并从用户那里检索租户 ID。目前,我从安全上下文中得到的只是 null 或 usernamepasswordauthenticationtoken,它只有一个用户名,即使这样,用户名也是 client_id 而不是特定用户的用户名(我使用 JWT 进行身份验证)
标签: java spring-boot javabeans servlet-filters multi-tenant