Java 从筛选器访问UserDetails(Spring) 规格
可以通过userDetailsService调用loadUserFromUsername的筛选器,以便从自定义UserDetails实例检索租户数据库详细信息 问题 无论过滤器优先级设置为什么,此自定义过滤器都会在安全过滤器之前运行,因此spring安全上下文未填充或为空。我已经确认,当我从控制器访问主体对象时,会填充此上下文 尝试 我已经将application.properties中的spring安全顺序设置为5,并且在注册此筛选器时,我使用了越来越大的值,但它以前总是运行。 我知道通用过滤器bean应该允许我将其设置为在安全配置之后,但我不知道如何将配置和过滤器移动到一个通用过滤器bean中 TenantFilter.java TenantFilterConfig.javaJava 从筛选器访问UserDetails(Spring) 规格,java,spring-boot,javabeans,servlet-filters,multi-tenant,Java,Spring Boot,Javabeans,Servlet Filters,Multi Tenant,可以通过userDetailsService调用loadUserFromUsername的筛选器,以便从自定义UserDetails实例检索租户数据库详细信息 问题 无论过滤器优先级设置为什么,此自定义过滤器都会在安全过滤器之前运行,因此spring安全上下文未填充或为空。我已经确认,当我从控制器访问主体对象时,会填充此上下文 尝试 我已经将application.properties中的spring安全顺序设置为5,并且在注册此筛选器时,我使用了越来越大的值,但它以前总是运行。 我知道通用过滤
找到了另一种非常有效的方法:方面 使用的切入点表达式意味着它围绕该项目中控制器包内所有类的所有方法调用运行 租户存储基于更安全地使用threadlocal来避免内存泄漏,因为这样,它总是会由于最终阻塞而被清除 快乐编码 TenantAspect.java
你的用户数据是什么?从principal获取数据后?@fabionoth User扩展了UserDetails,而我的loadUserFromUserName返回一个用户,因此我应该能够将其转换为User并从User检索租户id。目前,我从安全上下文中获得的信息要么是null,要么是用户名PasswordAuthenticationToken,它只有一个用户名,即使这样,用户名也是客户端id,而不是我使用JWTs进行身份验证的特定用户用户名
@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() {
}
}
@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();
}
}
@Component
@Aspect
public class TenantAspect {
private final
TenantStore tenantStore;
@Autowired
public TenantAspect(TenantStore tenantStore) {
this.tenantStore = tenantStore;
}
@Around(value = "execution(* com.things.stuff.controller..*(..))")
public Object assignForController(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
return assignTenant(proceedingJoinPoint);
}
private Object assignTenant(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
try {
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (user != null) tenantStore.setTenantId(user.getSchool().getCode());
} finally {
Object retVal;
retVal = proceedingJoinPoint.proceed();
tenantStore.clear();
return retVal;
}
}
}