0

我使用 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 调用的身份验证和授权失败:

  1. 没有为受保护端点提供凭据
  2. 提供了错误的凭据
  3. 提供了错误角色的正确凭据

结果显示org.springframework.security.access.AccessDeniedExceptioncase 1 和 3org.springframework.security.authentication.BadCredentialsException上升,case 2 上升,三种情况的返回值分别为:

  1. 带有 HTTP 状态 401 的 json 错误消息
  2. 重定向到 /login 端点的 HTTP 状态 302 返回
  3. 带有 HTTP 状态 403 的 json 错误消息

对于案例 2,该现象已在我的另一个问题中进行了解释。通常,这是因为默认错误端点会处理异常/error,并且在 Spring Boot 2 中,端点也受到保护,因此需要登录(详细信息 - Spring security 5 “Bad credentials”异常未与 errorDetails 一起显示)。

进一步的问题是为什么案例 1 和案例 3 不是由相同的机制处理?为什么默认错误处理程序不处理AccessDeniedExceptionwith/error端点?

4

1 回答 1

0

HTTP.401 或 »Unauthrized« 是因为安全上下文没有收到任何凭据。它还取决于被调用的 URL(静态页面、角色等)。通常浏览器会显示一个登录对话框。您的插图不包含此转发案例到登录表单的任何配置。

HTTP.403 或 »Forbidden« 已经在链的末端:错误的角色因此无法访问(没有转发,没有浏览器的对话框)。

您的 *SecurityConfig 是否驻留在不同的组件/ JAR 中?我假设不是,因为您使用@Order-annotation。如果您的意图是让两者同时处于活动状态并且它们在同一个 JAR 中,请将它们合并到一个 JAR 中。这使得在不牢记其中一个或另一个的情况下更清楚到底是什么意思。

我也只能猜测你的角色是如何表达的。至少存在三个不同的选项,例如@RolesAllowedSpring EL 或您所做的。请注意 Spring 的授予权限和角色之间的区别。如果没有配置,后者必须以“ROLE_”开头,否则可以在hasRoleSpringEL 中找到。其他一切最终都成为授予权限。

还有其他端点可能缺乏保护或现在无法访问,例如监控和健康端点。根据它们的配置,它可能会对所有端点产生影响(我只是假设它们将通过它们在 src/main/application.properties 或 .yaml 中的属性进行配置,而不使用任何 @Configuration-class。)

于 2020-10-03T08:24:10.073 回答