相同API的Spring security基本身份验证和表单登录
我想通过两种身份验证机制(基本身份验证和表单登录)访问我的所有API。我知道存在一些问题,但是,答案对我来说并不适用,我的用例有点不同 我的配置:相同API的Spring security基本身份验证和表单登录,spring,spring-mvc,spring-boot,spring-security,spring-security-oauth2,Spring,Spring Mvc,Spring Boot,Spring Security,Spring Security Oauth2,我想通过两种身份验证机制(基本身份验证和表单登录)访问我的所有API。我知道存在一些问题,但是,答案对我来说并不适用,我的用例有点不同 我的配置: @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig { @Configuration @Order(1) public static class SecurityConfigB
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {
@Configuration
@Order(1)
public static class SecurityConfigBasicAuth extends WebSecurityConfigurerAdapter {
final private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
@Autowired
public SecurityConfigBasicAuth(RestAuthenticationEntryPoint restAuthenticationEntryPoint,
@Qualifier("customUserDetailsService") UserDetailsService userDetailsService) {
this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
this.userDetailsService = userDetailsService;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
// @Bean authenticationProvider()
// @Bean passwordEncoder()
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and()
.cors()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable()
.httpBasic()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.formLogin().disable()
.logout().disable();
}
}
@Configuration
public static class SecurityConfigFormLogin extends WebSecurityConfigurerAdapter {
final private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
final private RestfulSavedRequestAwareAuthenticationSuccessHandler restfulSavedRequestAwareAuthenticationSuccessHandler;
final private CustomAuthenticationProvider customAuthenticationProvider;
@Autowired
public SecurityConfigFormLogin(RestAuthenticationEntryPoint restAuthenticationEntryPoint,
RestfulSavedRequestAwareAuthenticationSuccessHandler restfulSavedRequestAwareAuthenticationSuccessHandler,
CustomAuthenticationProvider hashAuthenticationProvider) {
this.restAuthenticationEntryPoint = restAuthenticationEntryPoint;
this.restfulSavedRequestAwareAuthenticationSuccessHandler = restfulSavedRequestAwareAuthenticationSuccessHandler;
this.customAuthenticationProvider = customAuthenticationProvider;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and()
.cors()
.and()
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.csrf().disable()
.httpBasic().disable()
.formLogin()
.usernameParameter("id1")
.passwordParameter("Id2")
.loginProcessingUrl("/test/login")
.successHandler(restfulSavedRequestAwareAuthenticationSuccessHandler)
.failureHandler(myFailureHandler())
.and()
.logout();
}
// @Bean myFailureHandler()
}
}
如您所见,我定义了两个“WebSecurity配置适配器”,一个用于基本身份验证,另一个用于表单登录。表单登录与REST兼容(不重定向,但提供HTTP响应)
问题如下:加载的第一个“WebSecurityConfigureAdapter”工作并覆盖第二个。上面的示例使使用basic auth成为可能,但我无法登录POST'/test/login',我得到一个:
{
"timestamp": 1534164906450,
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/test/login"
}
更新修复:关键是要使用“requestMatchers()”,请参见答案部分了解解决方案(如jzheaux所建议)好的,我就是这样修复的: 我将基本身份验证配置配置为:
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/api/**")
.and()
.cors()
.and()
.csrf().disable()
.httpBasic()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and();
}
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers(HttpMethod.POST, "/test/login")
.and()
.cors()
.and()
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.formLogin()
.usernameParameter("id1")
.passwordParameter("id2")
.loginProcessingUrl("/test/login")
.successHandler(authenticationSuccessHandler)
.failureHandler(myFailureHandler())
.and()
.logout();
}
如果不希望基本身份验证返回具有新JSESSIONID的新cookie,请添加:
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER)
.sessionFixation()
.migrateSession()
表单登录配置为:
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/api/**")
.and()
.cors()
.and()
.csrf().disable()
.httpBasic()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and();
}
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers(HttpMethod.POST, "/test/login")
.and()
.cors()
.and()
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.formLogin()
.usernameParameter("id1")
.passwordParameter("id2")
.loginProcessingUrl("/test/login")
.successHandler(authenticationSuccessHandler)
.failureHandler(myFailureHandler())
.and()
.logout();
}
现在,我可以通过表单登录配置进行身份验证,并使用cookie会话id调用/api/**(在基本身份验证配置中配置)。当然,我也可以使用基本的身份验证。在同一个端点上配置两组web安全过滤器不会有什么好处。我唯一能建议的是使用不同的URL,一个用于表单登录,一个用于基本身份验证-一旦经过身份验证,您就应该能够使用会话?其他的则不定义url路径。使用不同的url是什么意思?这两种身份验证都会产生特定的角色,在这些角色中,它们可以访问相同的API。这正是您所做的不同之处,也是它不起作用的原因。如果您确实需要两个不同的筛选器链,请先看http.requestMatchers()。这将允许您相当干净地按url拆分配置。您当前的配置可能存在的问题是,这些配置并没有完全覆盖它们,因为它们彼此合并(如果您不执行我上面建议的操作)。我很想亲自尝试一下,一个执行httpBasic,另一个执行httpBasic().disable的合并配置是什么。