spring - Spring Security 具有不同用户详细信息的多个 HTTPSecurity 服务在 Spring Boot 中不起作用
问题描述
我有两种类型的用户:应用程序用户和最终用户,我有单独的表格。现在,我想在这两个表上应用安全性。
我为应用程序用户提供了UserDetailsService的自定义实现:
@Component("applicationUserDetailsService")
public class ApplicationUserDetailsService implements UserDetailsService {}
而且,我为最终用户提供了另一个UserDetailsService自定义实现:
@Component("endUserDetailsService")
public class EndUserDetailsService implements UserDetailsService {}
现在,在下面的代码片段中,我为这两种类型的用户注册了两个端点。我已经注入了UserDetailsService的两个实现,并分别为应用程序和最终用户注册了@Overide configure(AuthenticationManagerBuilder auth)
方法。
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Import(SecurityProblemSupport.class)
public class SecurityConfiguration {
// Injected via Constructor Injection
private final EndUserDetailsService endUserDetailsService;
private final ApplicationUserDetailsService applicationUserDetailsService;
@Configuration
@Order(1)
public class ApplicationUserSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/test/**");
}
@Override
public void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.csrf()
.disable()
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.headers()
.frameOptions()
.disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.antMatcher("/api/customer/**")
.authorizeRequests()
.antMatchers("/api/customer/authenticate").permitAll()
.antMatchers("/api/customer/**")
.authenticated()
.and()
.apply(securityConfigurerAdapter());
// @formatter:on
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(endUserDetailsService);
}
}
//no @Order defaults to last
@Configuration
public class EndUserSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/test/**");
}
@Override
public void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.csrf()
.disable()
.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.headers()
.frameOptions()
.disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/authenticate").permitAll()
.antMatchers("/api/**").authenticated()
.and()
.apply(securityConfigurerAdapter());
// @formatter:on
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(applicationUserDetailsService);
}
}
private JWTConfigurer securityConfigurerAdapter() {
return new JWTConfigurer(tokenProvider);
}
}
而且,我正在尝试像这样对用户进行身份验证:
//Injected via Constructor Injection
private final AuthenticationManagerBuilder authenticationManagerBuilder;
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(loginVM.getUsername(), loginVM.getPassword());
Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
执行上述代码片段时,我得到空指针异常,因为authenticationManagerBuilder.getObject()
返回空值。而且,当我仅在使用UserDetailService实现而@Component("userDetailsService")
不是在安全配置中设置UserDetailServiceauth.userDetailsService("...")
时使用它时,它可以正常工作,但是通过这种方式,我无法从多个表中实现身份验证。
我想要实现的目标: 简单来说,我希望 spring security 从两个表中对用户进行身份验证。
解决方案
requestMatchers()
是您需要的调用,因为它允许您通过 URL 隔离适配器:
@Order(1)
@EnableWebSecurity
class EndUserConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/api/customer/**")
.and()
.authorizeRequests()
.antMatchers("/**").hasRole("CUSTOMER")
.and()
.apply(yourJointConfigurations());
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(endUserDetailsService);
}
}
关于AuthenticationManager
直接调用,如果您可以依靠现有的过滤器链为您完成工作,那将是理想的。例如,由于您是无状态的,HTTP Basic 可能更适合您,您可以将其应用于两种配置,而不是尝试使用专用/authenticate
端点。
推荐阅读
- python - 如何调试 pip 安装的工具?
- php - 如何使用 Ajax 成功创建动态表
- javascript - 如何使用 message.content 将不和谐的聊天消息保存到变量中
- html - css网格项目是否可以堆叠在一行中?
- resourcedictionary - WinUI 3 (UWP) 动态主题
- system-design - 如何让外部api调用更高效
- python - Timedelta 和 datetime 数据( TypeError: cannot convert the series to
) - python - python和pandas中是否有虚拟比较变量
- linux - gcc:错误:-o:没有这样的文件或目录 gcc:错误:文件名:没有这样的文件或目录 gcc:错误:无法识别的命令行选项'-pthreads'
- laravel-8 - 更新功能按钮不起作用 laravel 8(CRUD)