我使用 Spring Boot 2 和 Spring Security 5 创建了一个演示应用程序。源代码位于此处。
它提供了两种端点——HTML 网页和 REST api。因此,WebSecurityConfigurerAdapter
引入以下两个子类:
@Configuration
@Order(1)
public class ApiSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.antMatcher("/api/**")
.authorizeRequests()
.antMatchers("/api/admin**").hasRole("ADMIN")
.anyRequest().authenticated()
.and().httpBasic();
}
}
@Configuration
public class PageSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and().formLogin().loginPage("/login").permitAll().defaultSuccessUrl("/index")
.and().logout()
.invalidateHttpSession(true).deleteCookies("JSESSIONID")
.logoutSuccessUrl("/login").permitAll();
}
}
三种情况会导致 REST api 调用的身份验证和授权失败:
- 没有为受保护端点提供凭据
- 提供了错误的凭据
- 提供了错误角色的正确凭据
结果显示org.springframework.security.access.AccessDeniedException
case 1 和 3org.springframework.security.authentication.BadCredentialsException
上升,case 2 上升,三种情况的返回值分别为:
- 带有 HTTP 状态 401 的 json 错误消息
- 重定向到 /login 端点的 HTTP 状态 302 返回
- 带有 HTTP 状态 403 的 json 错误消息
对于案例 2,该现象已在我的另一个问题中进行了解释。通常,这是因为默认错误端点会处理异常/error
,并且在 Spring Boot 2 中,端点也受到保护,因此需要登录(详细信息 - Spring security 5 “Bad credentials”异常未与 errorDetails 一起显示)。
进一步的问题是为什么案例 1 和案例 3 不是由相同的机制处理?为什么默认错误处理程序不处理AccessDeniedException
with/error
端点?