Spring 为什么AccessDeniedException和AuthenticationException的处理方式不同
我用Spring Boot 2和Spring Security 5创建了一个演示应用程序。源位于 它提供了两种端点——HTML网页和REST API。因此,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
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调用的身份验证和授权失败:
org.springframework.security.access.AccessDeniedException
上升,在案例2中,org.springframework.security.authentication.BadCredentialsException
上升,三种情况的返回值为:
/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状态(trycurl)http://localhost:8080/api/data
)。这很好,工作正常。但是对于案例2,如果提供了错误的凭据,REST客户端希望通过json消息获得HTTP状态或不带json消息,但会被重定向到/login
端点。我不确定您到底想要什么。在您的问题案例中#2是通过异常和错误处理来解释的,错误处理由于受到保护而重定向到登录端点。这就是我的回答,由于您的安全配置,标准端点也受到保护。案例1和案例3已经通过HTTP状态的安全上下文得到了充分的处理,而不是异常诱导的重定向级联。对于案例2,我只是想问为什么它被重定向到/error
端点。根据基本身份验证失败时,BasicAuthenticationEntryPoint
将是最后一个调用,它只添加一个WWW-Authenticate
头并将HTTP状态设置为401(UNAUTHORIZED),这实际上是我想要的结果。但是,在我的应用程序中,在基本身份验证入口点
之后,我可以看到调用了/error
端点。所以,问题就如前面提到的那样。