Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring 为什么AccessDeniedException和AuthenticationException的处理方式不同_Spring_Spring Boot_Spring Security_Spring Boot Starter Security - Fatal编程技术网

Spring 为什么AccessDeniedException和AuthenticationException的处理方式不同

Spring 为什么AccessDeniedException和AuthenticationException的处理方式不同,spring,spring-boot,spring-security,spring-boot-starter-security,Spring,Spring Boot,Spring Security,Spring Boot Starter Security,我用Spring Boot 2和Spring Security 5创建了一个演示应用程序。源位于 它提供了两种端点——HTML网页和REST API。因此,websecurityConfigureAdapter的两个子类介绍如下: @Configuration @Order(1) public class ApiSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void config

我用Spring Boot 2和Spring Security 5创建了一个演示应用程序。源位于

它提供了两种端点——HTML网页和REST API。因此,
websecurityConfigureAdapter
的两个子类介绍如下:

@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和案例3中,
    org.springframework.security.access.AccessDeniedException
    上升,在案例2中,
    org.springframework.security.authentication.BadCredentialsException
    上升,三种情况的返回值为:

  • HTTP状态为401的json错误消息
  • HTTP状态302重定向到/返回登录端点
  • HTTP状态为403的json错误消息
  • 对于案例2,我的另一篇文章解释了这种现象。通常,这是因为异常将由默认错误端点
    /error
    处理,并且在Spring Boot 2中端点也受到保护,因此需要登录(详细信息--)


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

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

    HTTP.403或»禁止«已位于链的末端:角色错误,因此无法访问(无转发,无浏览器对话框)

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

    我也只能猜测你的角色是如何表达的。至少存在三种不同的选项,例如
    @RolesAllowed
    、Spring EL或与您一样。请注意Spring授予的权限和角色之间的区别。后者必须以“ROLE_uu”开头,如果没有配置,则可以通过
    hasRole
    SpringEL找到。其他一切最终都被授予了权力


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

    很抱歉,我没有看到客户端条件。实际上,这3种情况都适用于RESTAPI客户端,但不适用于浏览器。正如您所说,如果尝试在没有身份验证的情况下访问受保护的页面,浏览器将重定向到
    /login
    端点。然而,对于REST客户机,它只是通过一条json消息获取401状态(try
    curl)http://localhost:8080/api/data
    )。这很好,工作正常。但是对于案例2,如果提供了错误的凭据,REST客户端希望通过json消息获得HTTP状态或不带json消息,但会被重定向到
    /login
    端点。我不确定您到底想要什么。在您的问题案例中#2是通过异常和错误处理来解释的,错误处理由于受到保护而重定向到登录端点。这就是我的回答,由于您的安全配置,标准端点也受到保护。案例1和案例3已经通过HTTP状态的安全上下文得到了充分的处理,而不是异常诱导的重定向级联。对于案例2,我只是想问为什么它被重定向到
    /error
    端点。根据基本身份验证失败时,
    BasicAuthenticationEntryPoint
    将是最后一个调用,它只添加一个
    WWW-Authenticate
    头并将HTTP状态设置为401(UNAUTHORIZED),这实际上是我想要的结果。但是,在我的应用程序中,在
    基本身份验证入口点
    之后,我可以看到调用了
    /error
    端点。所以,问题就如前面提到的那样。